@cryptotaxi247 / netdata-1 / commits / 3590d9fc2

eBPF memory (#18232)

thiagoftsm committed Aug 16, 2024 at 15:23 UTC 3590d9fc2760cf604e6e5e845c9e96ed86210165
35 files changed +1085 -765
packaging/cmake/Modules/NetdataEBPFCORE.cmake
+2 -2
@@ -11,8 +11,8 @@ set(ebpf-co-re_SOURCE_DIR "${CMAKE_BINARY_DIR}/ebpf-co-re")
11 function(netdata_fetch_ebpf_co_re)
12 ExternalProject_Add(
13 ebpf-co-re
14 - URL https://github.com/netdata/ebpf-co-re/releases/download/v1.4.5/netdata-ebpf-co-re-glibc-v1.4.5.tar.xz
15 - URL_HASH SHA256=6937a167f6f8c65a0b0528a297df9944d15a649c9af34a70a678d4eabbbf22d1
14 + URL https://github.com/netdata/ebpf-co-re/releases/download/v1.4.5.1/netdata-ebpf-co-re-glibc-v1.4.5.1.tar.xz
15 + URL_HASH SHA256=10d49602c873932a4e0a3717a4af2137434b480d0170c2fb000ec70ae02f6e30
16 SOURCE_DIR "${ebpf-co-re_SOURCE_DIR}"
17 CONFIGURE_COMMAND ""
18 BUILD_COMMAND ""
packaging/cmake/Modules/NetdataEBPFLegacy.cmake
+4 -4
@@ -20,19 +20,19 @@ function(netdata_fetch_legacy_ebpf_code)
20 endif()
21
22 if(need_static)
23 - set(_hash 3f97034a595b5fd52ac4c5f43ce43085cc1391f39f2a281191efb15cc9666af4)
23 + set(_hash 1c0c8f1177514e9e21a23c28841406595e57b7cfacd93746ff2d6b25987b94a6)
24 set(_libc "static")
25 elseif(_libc STREQUAL "glibc")
26 - set(_hash 66094175e4d79b8a7222bc20d9e0d1bfbd37414891f88fc0113da53a97f8896a)
26 + set(_hash e365a76a2bb25190f1d91e4dea2cfc5ff5db63b5238fbfbc89f72755cf85a12c)
27 elseif(_libc STREQUAL "musl")
28 - set(_hash 58daad4a82cf3c511372892dd21b2825fcb138aad22c1db6bc889b1965439f5e)
28 + set(_hash ec14dcdfa29d4fba1cea6763740b9d37683515bde88a1a29b6e7c70ce01a604d)
29 else()
30 message(FATAL_ERROR "Could not determine libc implementation, unable to install eBPF legacy code.")
31 endif()
32
33 ExternalProject_Add(
34 ebpf-code-legacy
35 - URL https://github.com/netdata/kernel-collector/releases/download/v1.4.5/netdata-kernel-collector-${_libc}-v1.4.5.tar.xz
35 + URL https://github.com/netdata/kernel-collector/releases/download/v1.4.5.1/netdata-kernel-collector-${_libc}-v1.4.5.1.tar.xz
36 URL_HASH SHA256=${_hash}
37 SOURCE_DIR "${ebpf-legacy_SOURCE_DIR}"
38 CONFIGURE_COMMAND ""
src/collectors/ebpf.plugin/ebpf.c
+69 -28
@@ -30,6 +30,7 @@ int ebpf_nprocs;
30 int isrh = 0;
31 int main_thread_id = 0;
32 int process_pid_fd = -1;
33 +uint64_t collect_pids = 0;
34 static size_t global_iterations_counter = 1;
35 bool publish_internal_metrics = true;
36
@@ -996,7 +997,7 @@ static inline void ebpf_create_apps_for_module(ebpf_module_t *em, struct ebpf_ta
997 */
998 static void ebpf_create_apps_charts(struct ebpf_target *root)
999 {
999 - if (unlikely(!ebpf_all_pids))
1000 + if (unlikely(!ebpf_pids))
1001 return;
1002
1003 struct ebpf_target *w;
@@ -1028,21 +1029,15 @@ static void ebpf_create_apps_charts(struct ebpf_target *root)
1029 }
1030 }
1031
1031 - int i;
1032 - if (!newly_added) {
1032 + if (newly_added) {
1033 + int i;
1034 for (i = 0; i < EBPF_MODULE_FUNCTION_IDX ; i++) {
1034 - ebpf_module_t *current = &ebpf_modules[i];
1035 - if (current->apps_charts & NETDATA_EBPF_APPS_FLAG_CHART_CREATED)
1035 + if (!(collect_pids & (1<<i)))
1036 continue;
1037
1038 + ebpf_module_t *current = &ebpf_modules[i];
1039 ebpf_create_apps_for_module(current, root);
1040 }
1040 - return;
1041 - }
1042 -
1043 - for (i = 0; i < EBPF_MODULE_FUNCTION_IDX ; i++) {
1044 - ebpf_module_t *current = &ebpf_modules[i];
1045 - ebpf_create_apps_for_module(current, root);
1041 }
1042 }
1043
@@ -2680,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));
2683 - ebpf_all_pids = callocz((size_t)pid_max, sizeof(struct ebpf_pid_stat *));
2678 + ebpf_pids = callocz((size_t)pid_max, sizeof(ebpf_pid_data_t));
2679 ebpf_aral_init();
2680 }
2681
@@ -3014,7 +3009,7 @@ static int ebpf_load_collector_config(char *path, int *disable_cgroups, int upda
3009 /**
3010 * Set global variables reading environment variables
3011 */
3017 -void set_global_variables()
3012 +static void ebpf_set_global_variables()
3013 {
3014 // Get environment variables
3015 ebpf_plugin_dir = getenv("NETDATA_PLUGINS_DIR");
@@ -3418,6 +3413,11 @@ void ebpf_send_statistic_data()
3413 }
3414 ebpf_write_end_chart();
3415
3416 + ebpf_write_begin_chart(NETDATA_MONITORING_FAMILY, "monitoring_pid", "");
3417 + write_chart_dimension("user", ebpf_all_pids_count);
3418 + write_chart_dimension("kernel", ebpf_hash_table_pids_count);
3419 + ebpf_write_end_chart();
3420 +
3421 ebpf_write_begin_chart(NETDATA_MONITORING_FAMILY, NETDATA_EBPF_LIFE_TIME, "");
3422 for (i = 0; i < EBPF_MODULE_FUNCTION_IDX ; i++) {
3423 ebpf_module_t *wem = &ebpf_modules[i];
@@ -3489,6 +3489,37 @@ static void update_internal_metric_variable()
3489 publish_internal_metrics = false;
3490 }
3491
3492 +/**
3493 + * Create PIDS Chart
3494 + *
3495 + * Write to standard output current values for PIDSs charts.
3496 + *
3497 + * @param order order to display chart
3498 + * @param update_every time used to update charts
3499 + */
3500 +static void ebpf_create_pids_chart(int order, int update_every)
3501 +{
3502 + ebpf_write_chart_cmd(NETDATA_MONITORING_FAMILY,
3503 + "monitoring_pid",
3504 + "",
3505 + "Total number of monitored PIDs",
3506 + "pids",
3507 + NETDATA_EBPF_FAMILY,
3508 + NETDATA_EBPF_CHART_TYPE_LINE,
3509 + "netdata.ebpf_pids",
3510 + order,
3511 + update_every,
3512 + "main");
3513 +
3514 + ebpf_write_global_dimension("user",
3515 + "user",
3516 + ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
3517 +
3518 + ebpf_write_global_dimension("kernel",
3519 + "kernel",
3520 + ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
3521 +}
3522 +
3523 /**
3524 * Create Thread Chart
3525 *
@@ -3538,7 +3569,7 @@ static void ebpf_create_thread_chart(char *name,
3569 (char *)em->info.thread_name,
3570 ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
3571 }
3541 -}
3572 + }
3573
3574 /**
3575 * Create chart for Load Thread
@@ -3741,6 +3772,8 @@ static void ebpf_create_statistic_charts(int update_every)
3772 update_every,
3773 NULL);
3774
3775 + ebpf_create_pids_chart(NETDATA_EBPF_ORDER_PIDS, update_every);
3776 +
3777 ebpf_create_thread_chart(NETDATA_EBPF_LIFE_TIME,
3778 "Time remaining for thread.",
3779 "seconds",
@@ -3974,18 +4007,18 @@ int main(int argc, char **argv)
4007 clocks_init();
4008 nd_log_initialize_for_external_plugins(NETDATA_EBPF_PLUGIN_NAME);
4009
3977 - main_thread_id = gettid_cached();
3978 -
3979 - set_global_variables();
3980 - ebpf_parse_args(argc, argv);
3981 - ebpf_manage_pid(getpid());
3982 -
4010 + ebpf_set_global_variables();
4011 if (ebpf_can_plugin_load_code(running_on_kernel, NETDATA_EBPF_PLUGIN_NAME))
4012 return 2;
4013
4014 if (ebpf_adjust_memory_limit())
4015 return 3;
4016
4017 + main_thread_id = gettid_cached();
4018 +
4019 + ebpf_parse_args(argc, argv);
4020 + ebpf_manage_pid(getpid());
4021 +
4022 signal(SIGINT, ebpf_stop_threads);
4023 signal(SIGQUIT, ebpf_stop_threads);
4024 signal(SIGTERM, ebpf_stop_threads);
@@ -4018,7 +4051,7 @@ int main(int argc, char **argv)
4051 ebpf_cgroup_integration,
4052 NULL);
4053
4021 - int i;
4054 + uint32_t i;
4055 for (i = 0; ebpf_threads[i].name != NULL; i++) {
4056 struct netdata_static_thread *st = &ebpf_threads[i];
4057
@@ -4028,6 +4061,10 @@ int main(int argc, char **argv)
4061 if (em->enabled != NETDATA_THREAD_EBPF_NOT_RUNNING) {
4062 em->enabled = NETDATA_THREAD_EBPF_RUNNING;
4063 em->lifetime = EBPF_NON_FUNCTION_LIFE_TIME;
4064 +
4065 + if (em->functions.apps_routine && (em->apps_charts || em->cgroup_charts)) {
4066 + collect_pids |= 1<<i;
4067 + }
4068 st->thread = nd_thread_create(st->name, NETDATA_THREAD_OPTION_JOINABLE, st->start_routine, em);
4069 } else {
4070 em->lifetime = EBPF_DEFAULT_LIFETIME;
@@ -4038,7 +4075,7 @@ int main(int argc, char **argv)
4075 heartbeat_t hb;
4076 heartbeat_init(&hb);
4077 int update_apps_every = (int) EBPF_CFG_UPDATE_APPS_EVERY_DEFAULT;
4041 - int max_period = update_apps_every * EBPF_CLEANUP_FACTOR;
4078 + uint32_t max_period = EBPF_CLEANUP_FACTOR;
4079 int update_apps_list = update_apps_every - 1;
4080 int process_maps_per_core = ebpf_modules[EBPF_MODULE_PROCESS_IDX].maps_per_core;
4081 //Plugin will be killed when it receives a signal
@@ -4057,12 +4094,16 @@ int main(int argc, char **argv)
4094 if (++update_apps_list == update_apps_every) {
4095 update_apps_list = 0;
4096 pthread_mutex_lock(&lock);
4060 - pthread_mutex_lock(&collect_data_mutex);
4061 - ebpf_cleanup_exited_pids(max_period);
4062 - collect_data_for_all_processes(process_pid_fd, process_maps_per_core);
4063 -
4064 - ebpf_create_apps_charts(apps_groups_root_target);
4065 - pthread_mutex_unlock(&collect_data_mutex);
4097 + if (collect_pids) {
4098 + pthread_mutex_lock(&collect_data_mutex);
4099 + ebpf_parse_proc_files();
4100 + if (collect_pids & (1<<EBPF_MODULE_PROCESS_IDX)) {
4101 + collect_data_for_all_processes(process_pid_fd, process_maps_per_core, max_period);
4102 + }
4103 +
4104 + ebpf_create_apps_charts(apps_groups_root_target);
4105 + pthread_mutex_unlock(&collect_data_mutex);
4106 + }
4107 pthread_mutex_unlock(&lock);
4108 }
4109 }
src/collectors/ebpf.plugin/ebpf.d/cachestat.conf
+1 -1
@@ -37,6 +37,6 @@
37 # pid table size = 32768
38 ebpf type format = auto
39 ebpf co-re tracing = trampoline
40 - collect pid = all
40 + collect pid = real parent
41 # maps per core = yes
42 lifetime = 300
src/collectors/ebpf.plugin/ebpf.d/dcstat.conf
+1 -1
@@ -35,6 +35,6 @@
35 # pid table size = 32768
36 ebpf type format = auto
37 ebpf co-re tracing = trampoline
38 - collect pid = all
38 + collect pid = real parent
39 # maps per core = yes
40 lifetime = 300
src/collectors/ebpf.plugin/ebpf.d/fd.conf
+1
@@ -23,5 +23,6 @@
23 # pid table size = 32768
24 ebpf type format = auto
25 ebpf co-re tracing = trampoline
26 + collect pid = real parent
27 # maps per core = yes
28 lifetime = 300
src/collectors/ebpf.plugin/ebpf.d/oomkill.conf
+12
@@ -3,9 +3,21 @@
3 # `return : In the `return` mode, the eBPF collector monitors the same kernel functions as `entry`, but also creates
4 # new charts for the return of these functions, such as errors.
5 #
6 +# The eBPF collector also creates charts for each running application through an integration with the `apps.plugin`
7 +# or `cgroups.plugin`.
8 +# If you want to disable the integration with `apps.plugin` or `cgroups.plugin` along with the above charts, change
9 +# the setting `apps` and `cgroups` to 'no'.
10 +#
11 +# The `pid table size` defines the maximum number of PIDs stored inside the hash table.
12 +#
13 +# The `maps per core` defines if hash tables will be per core or not. This option is ignored on kernels older than 4.6.
14 +#
15 # The `lifetime` defines the time length a thread will run when it is enabled by a function.
16 #
17 [global]
18 # ebpf load mode = entry
19 # update every = 1
20 + ebpf type format = auto
21 + ebpf co-re tracing = trampoline
22 + collect pid = real parent
23 lifetime = 300
src/collectors/ebpf.plugin/ebpf.d/process.conf
+1 -1
@@ -26,6 +26,6 @@
26 # cgroups = no
27 # update every = 10
28 # pid table size = 32768
29 - collect pid = all
29 + collect pid = real parent
30 # maps per core = yes
31 lifetime = 300
src/collectors/ebpf.plugin/ebpf.d/shm.conf
+1 -1
@@ -31,7 +31,7 @@
31 # pid table size = 32768
32 ebpf type format = auto
33 ebpf co-re tracing = trampoline
34 - collect pid = all
34 + collect pid = real parent
35 # maps per core = yes
36 lifetime = 300
37
src/collectors/ebpf.plugin/ebpf.d/swap.conf
+1 -1
@@ -30,6 +30,6 @@
30 # pid table size = 32768
31 ebpf type format = auto
32 ebpf co-re tracing = trampoline
33 - collect pid = all
33 + collect pid = real parent
34 # maps per core = yes
35 lifetime = 300
src/collectors/ebpf.plugin/ebpf.d/vfs.conf
+1
@@ -31,5 +31,6 @@
31 # pid table size = 32768
32 ebpf type format = auto
33 ebpf co-re tracing = trampoline
34 + collect pid = real parent
35 # maps per core = yes
36 lifetime = 300
src/collectors/ebpf.plugin/ebpf.h
+2 -28
@@ -37,6 +37,7 @@
37 #define NETDATA_EBPF_OLD_CONFIG_FILE "ebpf.conf"
38 #define NETDATA_EBPF_CONFIG_FILE "ebpf.d.conf"
39
40 +extern size_t ebpf_hash_table_pids_count;
41 #ifdef LIBBPF_MAJOR_VERSION // BTF code
42 #include "cachestat.skel.h"
43 #include "dc.skel.h"
@@ -122,34 +123,6 @@ typedef struct netdata_ebpf_judy_pid_stats {
123 } netdata_ebpf_judy_pid_stats_t;
124
125 extern ebpf_module_t ebpf_modules[];
125 -enum ebpf_main_index {
126 - EBPF_MODULE_PROCESS_IDX,
127 - EBPF_MODULE_SOCKET_IDX,
128 - EBPF_MODULE_CACHESTAT_IDX,
129 - EBPF_MODULE_SYNC_IDX,
130 - EBPF_MODULE_DCSTAT_IDX,
131 - EBPF_MODULE_SWAP_IDX,
132 - EBPF_MODULE_VFS_IDX,
133 - EBPF_MODULE_FILESYSTEM_IDX,
134 - EBPF_MODULE_DISK_IDX,
135 - EBPF_MODULE_MOUNT_IDX,
136 - EBPF_MODULE_FD_IDX,
137 - EBPF_MODULE_HARDIRQ_IDX,
138 - EBPF_MODULE_SOFTIRQ_IDX,
139 - EBPF_MODULE_OOMKILL_IDX,
140 - EBPF_MODULE_SHM_IDX,
141 - EBPF_MODULE_MDFLUSH_IDX,
142 - EBPF_MODULE_FUNCTION_IDX,
143 - /* THREADS MUST BE INCLUDED BEFORE THIS COMMENT */
144 - EBPF_OPTION_ALL_CHARTS,
145 - EBPF_OPTION_VERSION,
146 - EBPF_OPTION_HELP,
147 - EBPF_OPTION_GLOBAL_CHART,
148 - EBPF_OPTION_RETURN_MODE,
149 - EBPF_OPTION_LEGACY,
150 - EBPF_OPTION_CORE,
151 - EBPF_OPTION_UNITTEST
152 -};
126
127 typedef struct ebpf_tracepoint {
128 bool enabled;
@@ -380,6 +353,7 @@ void ebpf_read_local_addresses_unsafe();
353 extern ebpf_filesystem_partitions_t localfs[];
354 extern ebpf_sync_syscalls_t local_syscalls[];
355 extern bool ebpf_plugin_exit;
356 +extern uint64_t collect_pids;
357
358 static inline bool ebpf_plugin_stop(void) {
359 return ebpf_plugin_exit || nd_thread_signaled_to_cancel();
src/collectors/ebpf.plugin/ebpf_apps.c
+152 -334
@@ -21,37 +21,11 @@ void ebpf_aral_init(void)
21 max_elements = NETDATA_EBPF_ALLOC_MIN_ELEMENTS;
22 }
23
24 - ebpf_aral_apps_pid_stat = ebpf_allocate_pid_aral("ebpf_pid_stat", sizeof(struct ebpf_pid_stat));
25 -
24 #ifdef NETDATA_DEV_MODE
25 netdata_log_info("Plugin is using ARAL with values %d", NETDATA_EBPF_ALLOC_MAX_PID);
26 #endif
27 }
28
31 -/**
32 - * eBPF pid stat get
33 - *
34 - * Get a ebpf_pid_stat entry to be used with a specific PID.
35 - *
36 - * @return it returns the address on success.
37 - */
38 -struct ebpf_pid_stat *ebpf_pid_stat_get(void)
39 -{
40 - struct ebpf_pid_stat *target = aral_mallocz(ebpf_aral_apps_pid_stat);
41 - memset(target, 0, sizeof(struct ebpf_pid_stat));
42 - return target;
43 -}
44 -
45 -/**
46 - * eBPF target release
47 - *
48 - * @param stat Release a target after usage.
49 - */
50 -void ebpf_pid_stat_release(struct ebpf_pid_stat *stat)
51 -{
52 - aral_freez(ebpf_aral_apps_pid_stat, stat);
53 -}
54 -
29 // ----------------------------------------------------------------------------
30 // internal flags
31 // handled in code (automatically set)
@@ -332,11 +306,11 @@ int ebpf_read_apps_groups_conf(struct ebpf_target **agdt, struct ebpf_target **a
306
307 #define MAX_CMDLINE 16384
308
335 -struct ebpf_pid_stat **ebpf_all_pids = NULL; // to avoid allocations, we pre-allocate the
336 - // the entire pid space.
337 -struct ebpf_pid_stat *ebpf_root_of_pids = NULL; // global list of all processes running
309 +ebpf_pid_data_t *ebpf_pids = NULL; // to avoid allocations, we pre-allocate the entire pid space.
310 +ebpf_pid_data_t *ebpf_pids_link_list = NULL; // global list of all processes running
311
339 -size_t ebpf_all_pids_count = 0; // the number of processes running
312 +size_t ebpf_all_pids_count = 0; // the number of processes running read from /proc
313 +size_t ebpf_hash_table_pids_count = 0; // the number of tasks in our hash tables
314
315 struct ebpf_target
316 *apps_groups_default_target = NULL, // the default target
@@ -388,110 +362,12 @@ static inline void debug_log_dummy(void)
362
363 #endif
364
391 -/**
392 - * Managed log
393 - *
394 - * Store log information if it is necessary.
395 - *
396 - * @param p the pid stat structure
397 - * @param log the log id
398 - * @param status the return from a function.
399 - *
400 - * @return It returns the status value.
401 - */
402 -static inline int managed_log(struct ebpf_pid_stat *p, uint32_t log, int status)
403 -{
404 - if (unlikely(!status)) {
405 - // netdata_log_error("command failed log %u, errno %d", log, errno);
406 -
407 - if (unlikely(debug_enabled || errno != ENOENT)) {
408 - if (unlikely(debug_enabled || !(p->log_thrown & log))) {
409 - p->log_thrown |= log;
410 - switch (log) {
411 - case PID_LOG_IO:
412 - netdata_log_error(
413 - "Cannot process %s/proc/%d/io (command '%s')", netdata_configured_host_prefix, p->pid,
414 - p->comm);
415 - break;
416 -
417 - case PID_LOG_STATUS:
418 - netdata_log_error(
419 - "Cannot process %s/proc/%d/status (command '%s')", netdata_configured_host_prefix, p->pid,
420 - p->comm);
421 - break;
422 -
423 - case PID_LOG_CMDLINE:
424 - netdata_log_error(
425 - "Cannot process %s/proc/%d/cmdline (command '%s')", netdata_configured_host_prefix, p->pid,
426 - p->comm);
427 - break;
428 -
429 - case PID_LOG_FDS:
430 - netdata_log_error(
431 - "Cannot process entries in %s/proc/%d/fd (command '%s')", netdata_configured_host_prefix,
432 - p->pid, p->comm);
433 - break;
434 -
435 - case PID_LOG_STAT:
436 - break;
437 -
438 - default:
439 - netdata_log_error("unhandled error for pid %d, command '%s'", p->pid, p->comm);
440 - break;
441 - }
442 - }
443 - }
444 - errno_clear();
445 - } else if (unlikely(p->log_thrown & log)) {
446 - // netdata_log_error("unsetting log %u on pid %d", log, p->pid);
447 - p->log_thrown &= ~log;
448 - }
449 -
450 - return status;
451 -}
452 -
453 -/**
454 - * Get PID entry
455 - *
456 - * Get or allocate the PID entry for the specified pid.
457 - *
458 - * @param pid the pid to search the data.
459 - * @param tgid the task group id
460 - *
461 - * @return It returns the pid entry structure
462 - */
463 -ebpf_pid_stat_t *ebpf_get_pid_entry(pid_t pid, pid_t tgid)
464 -{
465 - ebpf_pid_stat_t *ptr = ebpf_all_pids[pid];
466 - if (unlikely(ptr)) {
467 - if (!ptr->ppid && tgid)
468 - ptr->ppid = tgid;
469 - return ebpf_all_pids[pid];
470 - }
471 -
472 - struct ebpf_pid_stat *p = ebpf_pid_stat_get();
473 -
474 - if (likely(ebpf_root_of_pids))
475 - ebpf_root_of_pids->prev = p;
476 -
477 - p->next = ebpf_root_of_pids;
478 - ebpf_root_of_pids = p;
479 -
480 - p->pid = pid;
481 - p->ppid = tgid;
482 -
483 - ebpf_all_pids[pid] = p;
484 - ebpf_all_pids_count++;
485 -
486 - return p;
487 -}
488 -
365 /**
366 * Assign the PID to a target.
367 *
368 * @param p the pid_stat structure to assign for a target.
369 */
494 -static inline void assign_target_to_pid(struct ebpf_pid_stat *p)
370 +static inline void assign_target_to_pid(ebpf_pid_data_t *p)
371 {
372 targets_assignment_counter++;
373
@@ -499,6 +375,7 @@ static inline void assign_target_to_pid(struct ebpf_pid_stat *p)
375 size_t pclen = strlen(p->comm);
376
377 struct ebpf_target *w;
378 + bool assigned = false;
379 for (w = apps_groups_root_target; w; w = w->next) {
380 // if(debug_enabled || (p->target && p->target->debug_enabled)) debug_log_int("\t\tcomparing '%s' with '%s'", w->compare, p->comm);
381
@@ -521,9 +398,17 @@ static inline void assign_target_to_pid(struct ebpf_pid_stat *p)
398 if (debug_enabled || (p->target && p->target->debug_enabled))
399 debug_log_int("%s linked to target %s", p->comm, p->target->name);
400
401 + w->processes++;
402 + assigned = true;
403 +
404 break;
405 }
406 }
407 +
408 + if (!assigned) {
409 + apps_groups_default_target->processes++;
410 + p->target = apps_groups_default_target;
411 + }
412 }
413
414 // ----------------------------------------------------------------------------
@@ -532,22 +417,18 @@ static inline void assign_target_to_pid(struct ebpf_pid_stat *p)
417 /**
418 * Read cmd line from /proc/PID/cmdline
419 *
535 - * @param p the ebpf_pid_stat_structure.
420 + * @param p the ebpf_pid_data structure.
421 *
422 * @return It returns 1 on success and 0 otherwise.
423 */
539 -static inline int read_proc_pid_cmdline(struct ebpf_pid_stat *p)
424 +static inline int read_proc_pid_cmdline(ebpf_pid_data_t *p, char *cmdline)
425 {
541 - static char cmdline[MAX_CMDLINE + 1];
426 + char filename[FILENAME_MAX + 1];
427 + snprintfz(filename, FILENAME_MAX, "%s/proc/%d/cmdline", netdata_configured_host_prefix, p->pid);
428
429 int ret = 0;
544 - if (unlikely(!p->cmdline_filename)) {
545 - char filename[FILENAME_MAX + 1];
546 - snprintfz(filename, FILENAME_MAX, "%s/proc/%d/cmdline", netdata_configured_host_prefix, p->pid);
547 - p->cmdline_filename = strdupz(filename);
548 - }
430
550 - int fd = open(p->cmdline_filename, procfile_open_flags, 0666);
431 + int fd = open(filename, procfile_open_flags, 0666);
432 if (unlikely(fd == -1))
433 goto cleanup;
434
@@ -563,21 +444,12 @@ static inline int read_proc_pid_cmdline(struct ebpf_pid_stat *p)
444 cmdline[i] = ' ';
445 }
446
566 - debug_log("Read file '%s' contents: %s", p->cmdline_filename, p->cmdline);
447 + debug_log("Read file '%s' contents: %s", filename, p->cmdline);
448
449 ret = 1;
450
451 cleanup:
571 - // copy the command to the command line
572 - if (p->cmdline)
573 - freez(p->cmdline);
574 - p->cmdline = strdupz(p->comm);
575 -
576 - rw_spinlock_write_lock(&ebpf_judy_pid.index.rw_spinlock);
577 - netdata_ebpf_judy_pid_stats_t *pid_ptr = ebpf_get_pid_from_judy_unsafe(&ebpf_judy_pid.index.JudyLArray, p->pid);
578 - if (pid_ptr)
579 - pid_ptr->cmdline = p->cmdline;
580 - rw_spinlock_write_unlock(&ebpf_judy_pid.index.rw_spinlock);
452 + p->cmdline[0] = '\0';
453
454 return ret;
455 }
@@ -587,44 +459,43 @@ cleanup:
459 * Assign target to pid
460 *
461 * @param p the pid stat structure to store the data.
590 - * @param ptr an useless argument.
462 */
592 -static inline int read_proc_pid_stat(struct ebpf_pid_stat *p, void *ptr)
463 +static inline int read_proc_pid_stat(ebpf_pid_data_t *p)
464 {
594 - UNUSED(ptr);
595 -
596 - static procfile *ff = NULL;
597 -
598 - if (unlikely(!p->stat_filename)) {
599 - char filename[FILENAME_MAX + 1];
600 - snprintfz(filename, FILENAME_MAX, "%s/proc/%d/stat", netdata_configured_host_prefix, p->pid);
601 - p->stat_filename = strdupz(filename);
602 - }
465 + procfile *ff;
466
604 - int set_quotes = (!ff) ? 1 : 0;
467 + char filename[FILENAME_MAX + 1];
468 + int ret = 0;
469 + snprintfz(filename, FILENAME_MAX, "%s/proc/%u/stat", netdata_configured_host_prefix, p->pid);
470
471 struct stat statbuf;
607 - if (stat(p->stat_filename, &statbuf))
472 + if (stat(filename, &statbuf)) {
473 + p->has_proc_file = 0;
474 + p->thread_collecting &= ~(1<<EBPF_OPTION_ALL_CHARTS);
475 return 0;
476 + }
477
610 - ff = procfile_reopen(ff, p->stat_filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
478 + ff = procfile_open(filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
479 if (unlikely(!ff))
612 - return 0;
480 + goto cleanup_pid_stat;
481
614 - if (unlikely(set_quotes))
615 - procfile_set_open_close(ff, "(", ")");
482 + procfile_set_open_close(ff, "(", ")");
483
484 ff = procfile_readall(ff);
485 if (unlikely(!ff))
619 - return 0;
620 -
621 - p->last_stat_collected_usec = p->stat_collected_usec;
622 - p->stat_collected_usec = now_monotonic_usec();
623 - calls_counter++;
486 + goto cleanup_pid_stat;
487
488 char *comm = procfile_lineword(ff, 0, 1);
626 - p->ppid = (int32_t)str2pid_t(procfile_lineword(ff, 0, 3));
489 + int32_t ppid = (int32_t)str2pid_t(procfile_lineword(ff, 0, 3));
490 +
491 + if (p->ppid == ppid && p->target)
492 + goto without_cmdline_target;
493
494 + p->ppid = ppid;
495 +
496 + char cmdline[MAX_CMDLINE + 1];
497 + p->cmdline = cmdline;
498 + read_proc_pid_cmdline(p, cmdline);
499 if (strcmp(p->comm, comm) != 0) {
500 if (unlikely(debug_enabled)) {
501 if (p->comm[0])
@@ -634,58 +505,50 @@ static inline int read_proc_pid_stat(struct ebpf_pid_stat *p, void *ptr)
505 }
506
507 strncpyz(p->comm, comm, EBPF_MAX_COMPARE_NAME);
637 -
638 - // /proc/<pid>/cmdline
639 - if (likely(proc_pid_cmdline_is_needed))
640 - managed_log(p, PID_LOG_CMDLINE, read_proc_pid_cmdline(p));
641 -
642 - assign_target_to_pid(p);
508 }
509 + if (!p->target)
510 + assign_target_to_pid(p);
511 +
512 + p->cmdline = NULL;
513
514 if (unlikely(debug_enabled || (p->target && p->target->debug_enabled)))
515 debug_log_int(
647 - "READ PROC/PID/STAT: %s/proc/%d/stat, process: '%s' on target '%s' (dt=%llu)",
648 - netdata_configured_host_prefix, p->pid, p->comm, (p->target) ? p->target->name : "UNSET",
649 - p->stat_collected_usec - p->last_stat_collected_usec);
516 + "READ PROC/PID/STAT: %s/proc/%d/stat, process: '%s' on target '%s'",
517 + netdata_configured_host_prefix, p->pid, p->comm, (p->target) ? p->target->name : "UNSET");
518
651 - return 1;
519 +without_cmdline_target:
520 + p->has_proc_file = 1;
521 + p->not_updated = 0;
522 + ret = 1;
523 +cleanup_pid_stat:
524 + procfile_close(ff);
525 +
526 + return ret;
527 }
528
529 /**
530 * Collect data for PID
531 *
532 * @param pid the current pid that we are working
658 - * @param ptr a NULL value
533 *
534 * @return It returns 1 on success and 0 otherwise
535 */
662 -static inline int ebpf_collect_data_for_pid(pid_t pid, void *ptr)
536 +static inline int ebpf_collect_data_for_pid(pid_t pid)
537 {
538 if (unlikely(pid < 0 || pid > pid_max)) {
539 netdata_log_error("Invalid pid %d read (expected %d to %d). Ignoring process.", pid, 0, pid_max);
540 return 0;
541 }
542
669 - ebpf_pid_stat_t *p = ebpf_get_pid_entry(pid, 0);
670 - if (unlikely(!p || p->read))
671 - return 0;
672 - p->read = 1;
673 -
674 - if (unlikely(!managed_log(p, PID_LOG_STAT, read_proc_pid_stat(p, ptr))))
675 - // there is no reason to proceed if we cannot get its status
676 - return 0;
543 + ebpf_pid_data_t *p = ebpf_get_pid_data((uint32_t)pid, 0, NULL, EBPF_OPTION_ALL_CHARTS);
544 + read_proc_pid_stat(p);
545
546 // check its parent pid
679 - if (unlikely(p->ppid < 0 || p->ppid > pid_max)) {
680 - netdata_log_error("Pid %d (command '%s') states invalid parent pid %d. Using 0.", pid, p->comm, p->ppid);
547 + if (unlikely( p->ppid > pid_max)) {
548 + netdata_log_error("Pid %d (command '%s') states invalid parent pid %u. Using 0.", pid, p->comm, p->ppid);
549 p->ppid = 0;
550 }
551
684 - // mark it as updated
685 - p->updated = 1;
686 - p->keep = 0;
687 - p->keeploops = 0;
688 -
552 return 1;
553 }
554
@@ -694,14 +557,13 @@ static inline int ebpf_collect_data_for_pid(pid_t pid, void *ptr)
557 */
558 static inline void link_all_processes_to_their_parents(void)
559 {
697 - struct ebpf_pid_stat *p, *pp;
560 + ebpf_pid_data_t *p, *pp;
561
562 // link all children to their parents
563 // and update children count on parents
701 - for (p = ebpf_root_of_pids; p; p = p->next) {
564 + for (p = ebpf_pids_link_list; p; p = p->next) {
565 // for each process found
566
704 - p->sortlist = 0;
567 p->parent = NULL;
568
569 if (unlikely(!p->ppid)) {
@@ -709,16 +571,15 @@ static inline void link_all_processes_to_their_parents(void)
571 continue;
572 }
573
712 - pp = ebpf_all_pids[p->ppid];
713 - if (likely(pp)) {
574 + pp = &ebpf_pids[p->ppid];
575 + if (likely(pp->pid)) {
576 p->parent = pp;
577 pp->children_count++;
578
579 if (unlikely(debug_enabled || (p->target && p->target->debug_enabled)))
580 debug_log_int(
719 - "child %d (%s, %s) on target '%s' has parent %d (%s, %s).", p->pid, p->comm,
720 - p->updated ? "running" : "exited", (p->target) ? p->target->name : "UNSET", pp->pid, pp->comm,
721 - pp->updated ? "running" : "exited");
581 + "child %d (%s) on target '%s' has parent %d (%s).", p->pid, p->comm,
582 + (p->target) ? p->target->name : "UNSET", pp->pid, pp->comm);
583 } else {
584 p->parent = NULL;
585 debug_log("pid %d %s states parent %d, but the later does not exist.", p->pid, p->comm, p->ppid);
@@ -731,7 +592,7 @@ static inline void link_all_processes_to_their_parents(void)
592 */
593 static void apply_apps_groups_targets_inheritance(void)
594 {
734 - struct ebpf_pid_stat *p = NULL;
595 + struct ebpf_pid_data *p = NULL;
596
597 // children that do not have a target
598 // inherit their target from their parent
@@ -740,7 +601,7 @@ static void apply_apps_groups_targets_inheritance(void)
601 if (unlikely(debug_enabled))
602 loops++;
603 found = 0;
743 - for (p = ebpf_root_of_pids; p; p = p->next) {
604 + for (p = ebpf_pids_link_list; p; p = p->next) {
605 // if this process does not have a target
606 // and it has a parent
607 // and its parent has a target
@@ -751,7 +612,7 @@ static void apply_apps_groups_targets_inheritance(void)
612
613 if (debug_enabled || (p->target && p->target->debug_enabled))
614 debug_log_int(
754 - "TARGET INHERITANCE: %s is inherited by %d (%s) from its parent %d (%s).", p->target->name,
615 + "TARGET INHERITANCE: %s is inherited by %u (%s) from its parent %d (%s).", p->target->name,
616 p->pid, p->comm, p->parent->pid, p->parent->comm);
617 }
618 }
@@ -766,7 +627,7 @@ static void apply_apps_groups_targets_inheritance(void)
627 loops++;
628 found = 0;
629
769 - for (p = ebpf_root_of_pids; p; p = p->next) {
630 + for (p = ebpf_pids_link_list; p; p = p->next) {
631 if (unlikely(!p->sortlist && !p->children_count))
632 p->sortlist = sortlist++;
633
@@ -802,17 +663,15 @@ static void apply_apps_groups_targets_inheritance(void)
663 }
664
665 // init goes always to default target
805 - if (ebpf_all_pids[INIT_PID])
806 - ebpf_all_pids[INIT_PID]->target = apps_groups_default_target;
666 + ebpf_pids[INIT_PID].target = apps_groups_default_target;
667
668 // pid 0 goes always to default target
809 - if (ebpf_all_pids[0])
810 - ebpf_all_pids[0]->target = apps_groups_default_target;
669 + ebpf_pids[0].target = apps_groups_default_target;
670
671 // give a default target on all top level processes
672 if (unlikely(debug_enabled))
673 loops++;
815 - for (p = ebpf_root_of_pids; p; p = p->next) {
674 + for (p = ebpf_pids_link_list; p; p = p->next) {
675 // if the process is not merged itself
676 // then is is a top level process
677 if (unlikely(!p->merged && !p->target))
@@ -823,8 +682,7 @@ static void apply_apps_groups_targets_inheritance(void)
682 p->sortlist = sortlist++;
683 }
684
826 - if (ebpf_all_pids[1])
827 - ebpf_all_pids[1]->sortlist = sortlist++;
685 + ebpf_pids[1].sortlist = sortlist++;
686
687 // give a target to all merged child processes
688 found = 1;
@@ -832,7 +690,7 @@ static void apply_apps_groups_targets_inheritance(void)
690 if (unlikely(debug_enabled))
691 loops++;
692 found = 0;
835 - for (p = ebpf_root_of_pids; p; p = p->next) {
693 + for (p = ebpf_pids_link_list; p; p = p->next) {
694 if (unlikely(!p->target && p->merged && p->parent && p->parent->target)) {
695 p->target = p->parent->target;
696 found++;
@@ -872,29 +730,21 @@ static inline void post_aggregate_targets(struct ebpf_target *root)
730 *
731 * @param pid the PID that will be removed.
732 */
875 -static inline void ebpf_del_pid_entry(pid_t pid)
733 +void ebpf_del_pid_entry(pid_t pid)
734 {
877 - struct ebpf_pid_stat *p = ebpf_all_pids[pid];
878 -
879 - if (unlikely(!p)) {
880 - netdata_log_error("attempted to free pid %d that is not allocated.", pid);
881 - return;
882 - }
735 + ebpf_pid_data_t *p = &ebpf_pids[pid];
736
737 debug_log("process %d %s exited, deleting it.", pid, p->comm);
738
886 - if (ebpf_root_of_pids == p)
887 - ebpf_root_of_pids = p->next;
739 + if (ebpf_pids_link_list == p)
740 + ebpf_pids_link_list = p->next;
741
742 if (p->next)
743 p->next->prev = p->prev;
744 if (p->prev)
745 p->prev->next = p->next;
746
894 - freez(p->stat_filename);
895 - freez(p->status_filename);
896 - freez(p->io_filename);
897 - freez(p->cmdline_filename);
747 + memset(p, 0, sizeof(ebpf_pid_data_t));
748
749 rw_spinlock_write_lock(&ebpf_judy_pid.index.rw_spinlock);
750 netdata_ebpf_judy_pid_stats_t *pid_ptr = ebpf_get_pid_from_judy_unsafe(&ebpf_judy_pid.index.JudyLArray, p->pid);
@@ -914,57 +764,20 @@ static inline void ebpf_del_pid_entry(pid_t pid)
764 }
765 rw_spinlock_write_unlock(&ebpf_judy_pid.index.rw_spinlock);
766
917 - freez(p->cmdline);
918 - ebpf_pid_stat_release(p);
919 -
920 - ebpf_all_pids[pid] = NULL;
767 ebpf_all_pids_count--;
768 }
769
924 -/**
925 - * Get command string associated with a PID.
926 - * This can only safely be used when holding the `collect_data_mutex` lock.
927 - *
928 - * @param pid the pid to search the data.
929 - * @param n the maximum amount of bytes to copy into dest.
930 - * if this is greater than the size of the command, it is clipped.
931 - * @param dest the target memory buffer to write the command into.
932 - * @return -1 if the PID hasn't been scraped yet, 0 otherwise.
933 - */
934 -int get_pid_comm(pid_t pid, size_t n, char *dest)
935 -{
936 - struct ebpf_pid_stat *stat;
937 -
938 - stat = ebpf_all_pids[pid];
939 - if (unlikely(stat == NULL)) {
940 - return -1;
941 - }
942 -
943 - if (unlikely(n > sizeof(stat->comm))) {
944 - n = sizeof(stat->comm);
945 - }
946 -
947 - strncpyz(dest, stat->comm, n);
948 - return 0;
949 -}
950 -
770 /**
771 * Remove PIDs when they are not running more.
772 */
954 -void ebpf_cleanup_exited_pids(int max)
773 +static void ebpf_cleanup_exited_pids()
774 {
956 - struct ebpf_pid_stat *p = NULL;
957 -
958 - for (p = ebpf_root_of_pids; p;) {
959 - if (p->not_updated > max) {
960 - if (unlikely(debug_enabled && (p->keep || p->keeploops)))
961 - debug_log(" > CLEANUP cannot keep exited process %d (%s) anymore - removing it.", p->pid, p->comm);
962 -
963 - pid_t r = p->pid;
964 - p = p->next;
965 -
966 - ebpf_del_pid_entry(r);
775 + ebpf_pid_data_t *p = NULL;
776 + for (p = ebpf_pids_link_list; p;) {
777 + if (!p->has_proc_file) {
778 + ebpf_release_pid_data(p, 0, p->pid, EBPF_OPTION_ALL_CHARTS);
779 }
780 +
781 p = p->next;
782 }
783 }
@@ -974,14 +787,14 @@ void ebpf_cleanup_exited_pids(int max)
787 *
788 * @return It returns 0 on success and -1 otherwise.
789 */
977 -static inline void read_proc_filesystem()
790 +static int ebpf_read_proc_filesystem()
791 {
792 char dirname[FILENAME_MAX + 1];
793
794 snprintfz(dirname, FILENAME_MAX, "%s/proc", netdata_configured_host_prefix);
795 DIR *dir = opendir(dirname);
796 if (!dir)
984 - return;
797 + return -1;
798
799 struct dirent *de = NULL;
800
@@ -997,9 +810,11 @@ static inline void read_proc_filesystem()
810 if (unlikely(endptr == de->d_name || *endptr != '\0'))
811 continue;
812
1000 - ebpf_collect_data_for_pid(pid, NULL);
813 + ebpf_collect_data_for_pid(pid);
814 }
815 closedir(dir);
816 +
817 + return 0;
818 }
819
820 /**
@@ -1009,17 +824,17 @@ static inline void read_proc_filesystem()
824 * @param p the pid with information to update
825 * @param o never used
826 */
1012 -static inline void aggregate_pid_on_target(struct ebpf_target *w, struct ebpf_pid_stat *p, struct ebpf_target *o)
827 +static inline void aggregate_pid_on_target(struct ebpf_target *w, ebpf_pid_data_t *p, struct ebpf_target *o)
828 {
829 UNUSED(o);
830
1016 - if (unlikely(!p->updated)) {
831 + if (unlikely(!p->has_proc_file)) {
832 // the process is not running
833 return;
834 }
835
836 if (unlikely(!w)) {
1022 - netdata_log_error("pid %d %s was left without a target!", p->pid, p->comm);
837 + netdata_log_error("pid %u %s was left without a target!", p->pid, p->comm);
838 return;
839 }
840
@@ -1061,19 +876,18 @@ void ebpf_process_apps_accumulator(ebpf_process_stat_t *out, int maps_per_core)
876 void ebpf_process_sum_values_for_pids(ebpf_process_stat_t *process, struct ebpf_pid_on_target *root)
877 {
878 memset(process, 0, sizeof(ebpf_process_stat_t));
1064 - while (root) {
879 + for (; root; root = root->next) {
880 int32_t pid = root->pid;
1066 - ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(pid, 0);
1067 - if (local_pid) {
1068 - ebpf_process_stat_t *in = &local_pid->process;
1069 - process->task_err += in->task_err;
1070 - process->release_call += in->release_call;
1071 - process->exit_call += in->exit_call;
1072 - process->create_thread += in->create_thread;
1073 - process->create_process += in->create_process;
1074 - }
881 + ebpf_pid_data_t *local_pid = ebpf_get_pid_data(pid, 0, NULL, EBPF_MODULE_PROCESS_IDX);
882 + ebpf_publish_process_t *in = local_pid->process;
883 + if (!in)
884 + continue;
885
1076 - root = root->next;
886 + process->task_err += in->task_err;
887 + process->release_call += in->release_call;
888 + process->exit_call += in->exit_call;
889 + process->create_thread += in->create_thread;
890 + process->create_process += in->create_process;
891 }
892 }
893
@@ -1085,51 +899,38 @@ void ebpf_process_sum_values_for_pids(ebpf_process_stat_t *process, struct ebpf_
899 *
900 * @param tbl_pid_stats_fd The mapped file descriptor for the hash table.
901 * @param maps_per_core do I have hash maps per core?
902 + * @param max_period max period to wait before remove from hash table.
903 */
1089 -void collect_data_for_all_processes(int tbl_pid_stats_fd, int maps_per_core)
904 +void collect_data_for_all_processes(int tbl_pid_stats_fd, int maps_per_core, uint32_t max_period)
905 {
1091 - if (unlikely(!ebpf_all_pids))
906 + if (tbl_pid_stats_fd == -1)
907 return;
908
1094 - struct ebpf_pid_stat *pids = ebpf_root_of_pids; // global list of all processes running
1095 - while (pids) {
1096 - if (pids->updated_twice) {
1097 - pids->read = 0; // mark it as not read, so that collect_data_for_pid() will read it
1098 - pids->updated = 0;
1099 - pids->merged = 0;
1100 - pids->children_count = 0;
1101 - pids->parent = NULL;
1102 - } else {
1103 - if (pids->updated)
1104 - pids->updated_twice = 1;
1105 - }
1106 -
1107 - pids = pids->next;
1108 - }
1109 -
1110 - read_proc_filesystem();
1111 -
1112 - pids = ebpf_root_of_pids; // global list of all processes running
909 + size_t length = sizeof(ebpf_process_stat_t);
910 + if (maps_per_core)
911 + length *= ebpf_nprocs;
912
913 if (tbl_pid_stats_fd != -1) {
1115 - size_t length = sizeof(ebpf_process_stat_t);
1116 - if (maps_per_core)
1117 - length *= ebpf_nprocs;
914
915 uint32_t key = 0, next_key = 0;
916 while (bpf_map_get_next_key(tbl_pid_stats_fd, &key, &next_key) == 0) {
1121 - ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(key, 0);
1122 - if (!local_pid)
1123 - goto end_process_loop;
1124 -
1125 - ebpf_process_stat_t *w = &local_pid->process;
917 if (bpf_map_lookup_elem(tbl_pid_stats_fd, &key, process_stat_vector)) {
918 goto end_process_loop;
919 }
920
921 ebpf_process_apps_accumulator(process_stat_vector, maps_per_core);
922
1132 - memcpy(w, process_stat_vector, sizeof(ebpf_process_stat_t));
923 + ebpf_pid_data_t *local_pid = ebpf_get_pid_data(key, 0, NULL, EBPF_MODULE_PROCESS_IDX);
924 + ebpf_publish_process_t *w = local_pid->process;
925 + if (!w)
926 + local_pid->process = w = ebpf_process_allocate_publish();
927 +
928 + w->create_thread = process_stat_vector[0].create_thread;
929 + w->exit_call = process_stat_vector[0].exit_call;
930 + w->create_thread = process_stat_vector[0].create_thread;
931 + w->create_process = process_stat_vector[0].create_process;
932 + w->release_call = process_stat_vector[0].release_call;
933 + w->task_err = process_stat_vector[0].task_err;
934
935 end_process_loop:
936 memset(process_stat_vector, 0, length);
@@ -1137,24 +938,41 @@ end_process_loop:
938 }
939 }
940
941 + struct ebpf_target *w;
942 + for (w = apps_groups_root_target; w; w = w->next) {
943 + if (unlikely(!(w->processes)))
944 + continue;
945 +
946 + ebpf_process_sum_values_for_pids(&w->process, w->root_pid);
947 + }
948 +
949 +}
950 +
951 +/**
952 + *
953 + */
954 +void ebpf_parse_proc_files()
955 +{
956 + ebpf_pid_data_t *pids = ebpf_pids_link_list;
957 + while (pids) {
958 + pids->not_updated = EBPF_CLEANUP_FACTOR;
959 + pids->merged = 0;
960 + pids->children_count = 0;
961 +
962 + pids = pids->next;
963 + }
964 +
965 + if (ebpf_read_proc_filesystem())
966 + return;
967 +
968 link_all_processes_to_their_parents();
969
970 apply_apps_groups_targets_inheritance();
971
972 apps_groups_targets_count = zero_all_targets(apps_groups_root_target);
973
1146 - // this has to be done, before the cleanup
1147 - // // concentrate everything on the targets
1148 - for (pids = ebpf_root_of_pids; pids; pids = pids->next)
974 + for (pids = ebpf_pids_link_list; pids; pids = pids->next)
975 aggregate_pid_on_target(pids->target, pids, NULL);
976
1151 - post_aggregate_targets(apps_groups_root_target);
1152 -
1153 - struct ebpf_target *w;
1154 - for (w = apps_groups_root_target; w; w = w->next) {
1155 - if (unlikely(!(w->processes)))
1156 - continue;
1157 -
1158 - ebpf_process_sum_values_for_pids(&w->process, w->root_pid);
1159 - }
977 + ebpf_cleanup_exited_pids();
978 }
src/collectors/ebpf.plugin/ebpf_apps.h
+227 -13
@@ -39,10 +39,39 @@
39 #include "ebpf_swap.h"
40 #include "ebpf_vfs.h"
41
42 -#define EBPF_MAX_COMPARE_NAME 100
42 +#define EBPF_MAX_COMPARE_NAME 95
43 #define EBPF_MAX_NAME 100
44
45 -#define EBPF_CLEANUP_FACTOR 10
45 +#define EBPF_CLEANUP_FACTOR 2
46 +
47 +enum ebpf_main_index {
48 + EBPF_MODULE_PROCESS_IDX,
49 + EBPF_MODULE_SOCKET_IDX,
50 + EBPF_MODULE_CACHESTAT_IDX,
51 + EBPF_MODULE_SYNC_IDX,
52 + EBPF_MODULE_DCSTAT_IDX,
53 + EBPF_MODULE_SWAP_IDX,
54 + EBPF_MODULE_VFS_IDX,
55 + EBPF_MODULE_FILESYSTEM_IDX,
56 + EBPF_MODULE_DISK_IDX,
57 + EBPF_MODULE_MOUNT_IDX,
58 + EBPF_MODULE_FD_IDX,
59 + EBPF_MODULE_HARDIRQ_IDX,
60 + EBPF_MODULE_SOFTIRQ_IDX,
61 + EBPF_MODULE_OOMKILL_IDX,
62 + EBPF_MODULE_SHM_IDX,
63 + EBPF_MODULE_MDFLUSH_IDX,
64 + EBPF_MODULE_FUNCTION_IDX,
65 + /* THREADS MUST BE INCLUDED BEFORE THIS COMMENT */
66 + EBPF_OPTION_ALL_CHARTS,
67 + EBPF_OPTION_VERSION,
68 + EBPF_OPTION_HELP,
69 + EBPF_OPTION_GLOBAL_CHART,
70 + EBPF_OPTION_RETURN_MODE,
71 + EBPF_OPTION_LEGACY,
72 + EBPF_OPTION_CORE,
73 + EBPF_OPTION_UNITTEST
74 +};
75
76 // ----------------------------------------------------------------------------
77 // Structures used to read information from kernel ring
@@ -63,10 +92,21 @@ typedef struct ebpf_process_stat {
92
93 //Counter
94 uint32_t task_err;
66 -
67 - uint8_t removeme;
95 } ebpf_process_stat_t;
96
97 +typedef struct __attribute__((packed)) ebpf_publish_process {
98 + uint64_t ct;
99 +
100 + //Counter
101 + uint32_t exit_call;
102 + uint32_t release_call;
103 + uint32_t create_process;
104 + uint32_t create_thread;
105 +
106 + //Counter
107 + uint32_t task_err;
108 +} ebpf_publish_process_t;
109 +
110 // ----------------------------------------------------------------------------
111 // pid_stat
112 //
@@ -108,21 +148,198 @@ struct ebpf_target {
148 struct ebpf_target *target; // the one that will be reported to netdata
149 struct ebpf_target *next;
150 };
111 -
151 extern struct ebpf_target *apps_groups_default_target;
152 extern struct ebpf_target *apps_groups_root_target;
153 extern struct ebpf_target *users_root_target;
154 extern struct ebpf_target *groups_root_target;
155 +extern uint64_t collect_pids;
156 +
157 +typedef struct __attribute__((packed)) ebpf_pid_data {
158 + uint32_t pid;
159 + uint32_t ppid;
160 + uint64_t thread_collecting;
161 +
162 + char comm[EBPF_MAX_COMPARE_NAME + 1];
163 + char *cmdline;
164 +
165 + uint32_t has_proc_file;
166 + uint32_t not_updated;
167 + int children_count; // number of processes directly referencing this
168 + int merged;
169 + int sortlist; // higher numbers = top on the process tree
170 +
171 + struct ebpf_target *target; // the one that will be reported to netdata
172 + struct ebpf_pid_data *parent;
173 + struct ebpf_pid_data *prev;
174 + struct ebpf_pid_data *next;
175 +
176 + netdata_publish_fd_stat_t *fd;
177 + netdata_publish_swap_t *swap;
178 + netdata_publish_shm_t *shm; // this has a leak issue
179 + netdata_publish_dcstat_t *dc;
180 + netdata_publish_vfs_t *vfs;
181 + netdata_publish_cachestat_t *cachestat;
182 + ebpf_publish_process_t *process;
183 + ebpf_socket_publish_apps_t *socket;
184 +
185 +} ebpf_pid_data_t;
186 +
187 +extern ebpf_pid_data_t *ebpf_pids;
188 +extern ebpf_pid_data_t *ebpf_pids_link_list;
189 +extern size_t ebpf_all_pids_count;
190 +extern size_t ebpf_hash_table_pids_count;
191 +void ebpf_del_pid_entry(pid_t pid);
192 +
193 +static inline void *ebpf_cachestat_allocate_publish()
194 +{
195 + ebpf_hash_table_pids_count++;
196 + return callocz(1, sizeof(netdata_publish_cachestat_t));
197 +}
198 +
199 +static inline void ebpf_cachestat_release_publish(netdata_publish_cachestat_t *ptr)
200 +{
201 + ebpf_hash_table_pids_count--;
202 + freez(ptr);
203 +}
204 +
205 +static inline void *ebpf_dcallocate_publish()
206 +{
207 + ebpf_hash_table_pids_count++;
208 + return callocz(1, sizeof(netdata_publish_dcstat_t));
209 +}
210 +
211 +static inline void ebpf_dc_release_publish(netdata_publish_dcstat_t *ptr)
212 +{
213 + ebpf_hash_table_pids_count--;
214 + freez(ptr);
215 +}
216 +
217 +static inline void *ebpf_fd_allocate_publish()
218 +{
219 + ebpf_hash_table_pids_count++;
220 + return callocz(1, sizeof(netdata_publish_fd_stat_t));
221 +}
222 +
223 +static inline void ebpf_fd_release_publish(netdata_publish_fd_stat_t *ptr)
224 +{
225 + ebpf_hash_table_pids_count--;
226 + freez(ptr);
227 +}
228 +
229 +static inline void *ebpf_shm_allocate_publish()
230 +{
231 + ebpf_hash_table_pids_count++;
232 + return callocz(1, sizeof(netdata_publish_shm_t));
233 +}
234 +
235 +static inline void ebpf_shm_release_publish(netdata_publish_shm_t *ptr)
236 +{
237 + ebpf_hash_table_pids_count--;
238 + freez(ptr);
239 +}
240 +
241 +static inline void *ebpf_socket_allocate_publish()
242 +{
243 + ebpf_hash_table_pids_count++;
244 + return callocz(1, sizeof(ebpf_socket_publish_apps_t));
245 +}
246 +
247 +static inline void ebpf_socket_release_publish(ebpf_socket_publish_apps_t *ptr)
248 +{
249 + ebpf_hash_table_pids_count--;
250 + freez(ptr);
251 +}
252 +
253 +static inline void *ebpf_swap_allocate_publish_swap()
254 +{
255 + ebpf_hash_table_pids_count++;
256 + return callocz(1, sizeof(netdata_publish_swap_t));
257 +}
258 +
259 +static inline void ebpf_release_publish_swap(netdata_publish_swap_t *ptr)
260 +{
261 + ebpf_hash_table_pids_count--;
262 + freez(ptr);
263 +}
264 +
265 +static inline void *ebpf_vfs_allocate_publish()
266 +{
267 + ebpf_hash_table_pids_count++;
268 + return callocz(1, sizeof(netdata_publish_vfs_t));
269 +}
270 +
271 +static inline void ebpf_vfs_release_publish(netdata_publish_vfs_t *ptr)
272 +{
273 + ebpf_hash_table_pids_count--;
274 + freez(ptr);
275 +}
276 +
277 +static inline void *ebpf_process_allocate_publish()
278 +{
279 + ebpf_hash_table_pids_count++;
280 + return callocz(1, sizeof(ebpf_publish_process_t));
281 +}
282 +
283 +static inline void ebpf_process_release_publish(ebpf_publish_process_t *ptr)
284 +{
285 + ebpf_hash_table_pids_count--;
286 + freez(ptr);
287 +}
288 +
289 +static inline ebpf_pid_data_t *ebpf_get_pid_data(uint32_t pid, uint32_t tgid, char *name, uint32_t idx) {
290 + // To add pids to target here will do host very slow
291 +
292 + ebpf_pid_data_t *ptr = &ebpf_pids[pid];
293 + // The caller is getting data to work.
294 + if (!name && idx != EBPF_OPTION_ALL_CHARTS)
295 + return ptr;
296 +
297 + ptr->thread_collecting |= 1<<idx;
298 + if (ptr->pid == pid) {
299 + return ptr;
300 + }
301 +
302 + ptr->pid = pid;
303 + ptr->ppid = tgid;
304 +
305 + if (name)
306 + strncpyz(ptr->comm, name, EBPF_MAX_COMPARE_NAME);
307 +
308 + if (idx == EBPF_OPTION_ALL_CHARTS) {
309 + // We are going to use only with pids listed in /proc, other PIDs are associated to it
310 + if (likely(ebpf_pids_link_list))
311 + ebpf_pids_link_list->prev = ptr;
312 +
313 + ptr->next = ebpf_pids_link_list;
314 + ebpf_pids_link_list = ptr;
315 + }
316 +
317 + ebpf_all_pids_count++;
318 +
319 + return ptr;
320 +}
321 +
322 +static inline void ebpf_release_pid_data(ebpf_pid_data_t *eps, int fd, uint32_t key, uint32_t idx)
323 +{
324 + if (fd) {
325 + bpf_map_delete_elem(fd, &key);
326 + }
327 + eps->thread_collecting &= ~(1<<idx);
328 + if (!eps->thread_collecting && !eps->has_proc_file) {
329 + ebpf_del_pid_entry((pid_t)key);
330 + }
331 +}
332
333 typedef struct ebpf_pid_stat {
118 - int32_t pid;
334 + uint32_t pid;
335 + uint64_t thread_collecting;
336 char comm[EBPF_MAX_COMPARE_NAME + 1];
337 char *cmdline;
338
339 uint32_t log_thrown;
340
341 // char state;
125 - int32_t ppid;
342 + uint32_t ppid;
343
344 int children_count; // number of processes directly referencing this
345 unsigned char keep : 1; // 1 when we need to keep this process in memory even after it exited
@@ -199,8 +416,6 @@ static inline void debug_log_int(const char *fmt, ...)
416 // ----------------------------------------------------------------------------
417 // Exported variabled and functions
418 //
202 -extern struct ebpf_pid_stat **ebpf_all_pids;
203 -
419 int ebpf_read_apps_groups_conf(struct ebpf_target **apps_groups_default_target,
420 struct ebpf_target **apps_groups_root_target,
421 const char *path,
@@ -216,7 +431,7 @@ int ebpf_read_hash_table(void *ep, int fd, uint32_t pid);
431
432 int get_pid_comm(pid_t pid, size_t n, char *dest);
433
219 -void collect_data_for_all_processes(int tbl_pid_stats_fd, int maps_per_core);
434 +void collect_data_for_all_processes(int tbl_pid_stats_fd, int maps_per_core, uint32_t max_period);
435 void ebpf_process_apps_accumulator(ebpf_process_stat_t *out, int maps_per_core);
436
437 // The default value is at least 32 times smaller than maximum number of PIDs allowed on system,
@@ -227,8 +442,7 @@ void ebpf_process_apps_accumulator(ebpf_process_stat_t *out, int maps_per_core);
442 #define NETDATA_EBPF_ALLOC_MIN_ELEMENTS 256
443
444 // ARAL Sectiion
230 -extern void ebpf_aral_init(void);
231 -extern ebpf_pid_stat_t *ebpf_get_pid_entry(pid_t pid, pid_t tgid);
445 +void ebpf_aral_init(void);
446 extern ebpf_process_stat_t *process_stat_vector;
447
448 extern ARAL *ebpf_aral_vfs_pid;
@@ -240,7 +454,7 @@ extern ARAL *ebpf_aral_shm_pid;
454 void ebpf_shm_aral_init();
455 netdata_publish_shm_t *ebpf_shm_stat_get(void);
456 void ebpf_shm_release(netdata_publish_shm_t *stat);
243 -void ebpf_cleanup_exited_pids(int max);
457 +void ebpf_parse_proc_files();
458
459 // ARAL Section end
460
src/collectors/ebpf.plugin/ebpf_cachestat.c
+48 -40
@@ -528,6 +528,10 @@ static void ebpf_cachestat_exit(void *pptr)
528 ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
529 if(!em) return;
530
531 + pthread_mutex_lock(&lock);
532 + collect_pids &= ~(1<<EBPF_MODULE_CACHESTAT_IDX);
533 + pthread_mutex_unlock(&lock);
534 +
535 if (ebpf_read_cachestat.thread)
536 nd_thread_signal_cancel(ebpf_read_cachestat.thread);
537
@@ -677,6 +681,9 @@ static void cachestat_apps_accumulator(netdata_cachestat_pid_t *out, int maps_pe
681 total->mark_page_accessed += w->mark_page_accessed;
682 if (w->ct > ct)
683 ct = w->ct;
684 +
685 + if (!total->name[0] && w->name[0])
686 + strncpyz(total->name, w->name, sizeof(total->name) - 1);
687 }
688 total->ct = ct;
689 }
@@ -692,13 +699,14 @@ static void cachestat_apps_accumulator(netdata_cachestat_pid_t *out, int maps_pe
699 static inline void cachestat_save_pid_values(netdata_publish_cachestat_t *out, netdata_cachestat_pid_t *in)
700 {
701 out->ct = in->ct;
695 - if (!out->current.mark_page_accessed) {
696 - memcpy(&out->current, &in[0], sizeof(netdata_cachestat_pid_t));
697 - return;
702 + if (out->current.mark_page_accessed) {
703 + memcpy(&out->prev, &out->current, sizeof(netdata_cachestat_t));
704 }
705
700 - memcpy(&out->prev, &out->current, sizeof(netdata_cachestat_pid_t));
701 - memcpy(&out->current, &in[0], sizeof(netdata_cachestat_pid_t));
706 + out->current.account_page_dirtied = in[0].account_page_dirtied;
707 + out->current.add_to_page_cache_lru = in[0].add_to_page_cache_lru;
708 + out->current.mark_buffer_dirty = in[0].mark_buffer_dirty;
709 + out->current.mark_page_accessed = in[0].mark_page_accessed;
710 }
711
712 /**
@@ -707,8 +715,9 @@ static inline void cachestat_save_pid_values(netdata_publish_cachestat_t *out, n
715 * Read the apps table and store data inside the structure.
716 *
717 * @param maps_per_core do I need to read all cores?
718 + * @param max_period limit of iterations without updates before remove data from hash table
719 */
711 -static void ebpf_read_cachestat_apps_table(int maps_per_core, int max_period)
720 +static void ebpf_read_cachestat_apps_table(int maps_per_core, uint32_t max_period)
721 {
722 netdata_cachestat_pid_t *cv = cachestat_vector;
723 int fd = cachestat_maps[NETDATA_CACHESTAT_PID_STATS].map_fd;
@@ -724,17 +733,18 @@ static void ebpf_read_cachestat_apps_table(int maps_per_core, int max_period)
733
734 cachestat_apps_accumulator(cv, maps_per_core);
735
727 - ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(key, cv->tgid);
728 - if (!local_pid)
729 - goto end_cachestat_loop;
736 + ebpf_pid_data_t *local_pid = ebpf_get_pid_data(key, cv->tgid, cv->name, EBPF_MODULE_CACHESTAT_IDX);
737 + netdata_publish_cachestat_t *publish = local_pid->cachestat;
738 + if (!publish)
739 + local_pid->cachestat = publish = ebpf_cachestat_allocate_publish();
740
731 - netdata_publish_cachestat_t *publish = &local_pid->cachestat;
741 if (!publish->ct || publish->ct != cv->ct){
742 cachestat_save_pid_values(publish, cv);
743 local_pid->not_updated = 0;
744 } else if (++local_pid->not_updated >= max_period) {
736 - bpf_map_delete_elem(fd, &key);
737 - local_pid->not_updated = 0;
745 + ebpf_release_pid_data(local_pid, fd, key, EBPF_MODULE_CACHESTAT_IDX);
746 + ebpf_cachestat_release_publish(publish);
747 + local_pid->cachestat = NULL;
748 }
749
750 end_cachestat_loop:
@@ -759,13 +769,14 @@ static void ebpf_update_cachestat_cgroup()
769 struct pid_on_target2 *pids;
770 for (pids = ect->pids; pids; pids = pids->next) {
771 int pid = pids->pid;
762 - netdata_cachestat_pid_t *out = &pids->cachestat;
763 - ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(pid, 0);
764 - if (local_pid) {
765 - netdata_publish_cachestat_t *in = &local_pid->cachestat;
772 + netdata_publish_cachestat_t *out = &pids->cachestat;
773
767 - memcpy(out, &in->current, sizeof(netdata_cachestat_pid_t));
768 - }
774 + ebpf_pid_data_t *local_pid = ebpf_get_pid_data(pid, 0, NULL, EBPF_MODULE_CACHESTAT_IDX);
775 + netdata_publish_cachestat_t *in = local_pid->cachestat;
776 + if (!in)
777 + continue;
778 +
779 + memcpy(&out->current, &in->current, sizeof(netdata_cachestat_t));
780 }
781 }
782 pthread_mutex_unlock(&mutex_cgroup_shm);
@@ -784,20 +795,19 @@ void ebpf_cachestat_sum_pids(netdata_publish_cachestat_t *publish, struct ebpf_p
795 memcpy(&publish->prev, &publish->current,sizeof(publish->current));
796 memset(&publish->current, 0, sizeof(publish->current));
797
787 - netdata_cachestat_pid_t *dst = &publish->current;
788 - while (root) {
798 + netdata_cachestat_t *dst = &publish->current;
799 + for (; root; root = root->next) {
800 int32_t pid = root->pid;
790 - ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(pid, 0);
791 - if (local_pid) {
792 - netdata_publish_cachestat_t *w = &local_pid->cachestat;
793 - netdata_cachestat_pid_t *src = &w->current;
794 - dst->account_page_dirtied += src->account_page_dirtied;
795 - dst->add_to_page_cache_lru += src->add_to_page_cache_lru;
796 - dst->mark_buffer_dirty += src->mark_buffer_dirty;
797 - dst->mark_page_accessed += src->mark_page_accessed;
798 - }
801 + ebpf_pid_data_t *local_pid = ebpf_get_pid_data(pid, 0, NULL, EBPF_MODULE_CACHESTAT_IDX);
802 + netdata_publish_cachestat_t *w = local_pid->cachestat;
803 + if (!w)
804 + continue;
805
800 - root = root->next;
806 + netdata_cachestat_t *src = &w->current;
807 + dst->account_page_dirtied += src->account_page_dirtied;
808 + dst->add_to_page_cache_lru += src->add_to_page_cache_lru;
809 + dst->mark_buffer_dirty += src->mark_buffer_dirty;
810 + dst->mark_page_accessed += src->mark_page_accessed;
811 }
812 }
813
@@ -834,7 +844,7 @@ void *ebpf_read_cachestat_thread(void *ptr)
844
845 int maps_per_core = em->maps_per_core;
846 int update_every = em->update_every;
837 - int max_period = update_every * EBPF_CLEANUP_FACTOR;
847 + uint32_t max_period = EBPF_CLEANUP_FACTOR;
848
849 int counter = update_every - 1;
850
@@ -1020,8 +1030,8 @@ void ebpf_cache_send_apps_data(struct ebpf_target *root)
1030 if (unlikely(!(w->charts_created & (1<<EBPF_MODULE_CACHESTAT_IDX))))
1031 continue;
1032
1023 - netdata_cachestat_pid_t *current = &w->cachestat.current;
1024 - netdata_cachestat_pid_t *prev = &w->cachestat.prev;
1033 + netdata_cachestat_t *current = &w->cachestat.current;
1034 + netdata_cachestat_t *prev = &w->cachestat.prev;
1035
1036 uint64_t mpa = current->mark_page_accessed - prev->mark_page_accessed;
1037 uint64_t mbd = current->mark_buffer_dirty - prev->mark_buffer_dirty;
@@ -1067,16 +1077,14 @@ void ebpf_cachestat_sum_cgroup_pids(netdata_publish_cachestat_t *publish, struct
1077 memcpy(&publish->prev, &publish->current,sizeof(publish->current));
1078 memset(&publish->current, 0, sizeof(publish->current));
1079
1070 - netdata_cachestat_pid_t *dst = &publish->current;
1071 - while (root) {
1072 - netdata_cachestat_pid_t *src = &root->cachestat;
1080 + netdata_cachestat_t *dst = &publish->current;
1081 + for (; root; root = root->next) {
1082 + netdata_cachestat_t *src = &root->cachestat.current;
1083
1084 dst->account_page_dirtied += src->account_page_dirtied;
1085 dst->add_to_page_cache_lru += src->add_to_page_cache_lru;
1086 dst->mark_buffer_dirty += src->mark_buffer_dirty;
1087 dst->mark_page_accessed += src->mark_page_accessed;
1078 -
1079 - root = root->next;
1088 }
1089 }
1090
@@ -1091,8 +1099,8 @@ void ebpf_cachestat_calc_chart_values()
1099 for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
1100 ebpf_cachestat_sum_cgroup_pids(&ect->publish_cachestat, ect->pids);
1101
1094 - netdata_cachestat_pid_t *current = &ect->publish_cachestat.current;
1095 - netdata_cachestat_pid_t *prev = &ect->publish_cachestat.prev;
1102 + netdata_cachestat_t *current = &ect->publish_cachestat.current;
1103 + netdata_cachestat_t *prev = &ect->publish_cachestat.prev;
1104
1105 uint64_t mpa = current->mark_page_accessed - prev->mark_page_accessed;
1106 uint64_t mbd = current->mark_buffer_dirty - prev->mark_buffer_dirty;
src/collectors/ebpf.plugin/ebpf_cachestat.h
+15 -8
@@ -69,20 +69,27 @@ enum cachestat_tables {
69 NETDATA_CACHESTAT_CTRL
70 };
71
72 -typedef struct netdata_publish_cachestat_pid {
72 +typedef struct netdata_cachestat_pid {
73 uint64_t ct;
74 uint32_t tgid;
75 uint32_t uid;
76 uint32_t gid;
77 char name[TASK_COMM_LEN];
78
79 - uint64_t add_to_page_cache_lru;
80 - uint64_t mark_page_accessed;
81 - uint64_t account_page_dirtied;
82 - uint64_t mark_buffer_dirty;
79 + uint32_t add_to_page_cache_lru;
80 + uint32_t mark_page_accessed;
81 + uint32_t account_page_dirtied;
82 + uint32_t mark_buffer_dirty;
83 } netdata_cachestat_pid_t;
84
85 -typedef struct netdata_publish_cachestat {
85 +typedef struct __attribute__((packed)) netdata_cachestat {
86 + uint32_t add_to_page_cache_lru;
87 + uint32_t mark_page_accessed;
88 + uint32_t account_page_dirtied;
89 + uint32_t mark_buffer_dirty;
90 +} netdata_cachestat_t;
91 +
92 +typedef struct __attribute__((packed)) netdata_publish_cachestat {
93 uint64_t ct;
94
95 long long ratio;
@@ -90,8 +97,8 @@ typedef struct netdata_publish_cachestat {
97 long long hit;
98 long long miss;
99
93 - netdata_cachestat_pid_t current;
94 - netdata_cachestat_pid_t prev;
100 + netdata_cachestat_t current;
101 + netdata_cachestat_t prev;
102 } netdata_publish_cachestat_t;
103
104 void *ebpf_cachestat_thread(void *ptr);
src/collectors/ebpf.plugin/ebpf_cgroup.h
+5 -5
@@ -14,13 +14,13 @@ struct pid_on_target2 {
14 int updated;
15
16 netdata_publish_swap_t swap;
17 - netdata_fd_stat_t fd;
17 + netdata_publish_fd_stat_t fd;
18 netdata_publish_vfs_t vfs;
19 - ebpf_process_stat_t ps;
19 + ebpf_publish_process_t ps;
20 netdata_dcstat_pid_t dc;
21 netdata_publish_shm_t shm;
22 netdata_socket_t socket;
23 - netdata_cachestat_pid_t cachestat;
23 + netdata_publish_cachestat_t cachestat;
24
25 struct pid_on_target2 *next;
26 };
@@ -55,9 +55,9 @@ typedef struct ebpf_cgroup_target {
55 uint32_t updated;
56
57 netdata_publish_swap_t publish_systemd_swap;
58 - netdata_fd_stat_t publish_systemd_fd;
58 + netdata_publish_fd_stat_t publish_systemd_fd;
59 netdata_publish_vfs_t publish_systemd_vfs;
60 - ebpf_process_stat_t publish_systemd_ps;
60 + ebpf_publish_process_t publish_systemd_ps;
61 netdata_publish_dcstat_t publish_dc;
62 int oomkill;
63 netdata_publish_shm_t publish_shm;
src/collectors/ebpf.plugin/ebpf_dcstat.c
+46 -33
@@ -456,6 +456,10 @@ static void ebpf_dcstat_exit(void *pptr)
456 ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
457 if(!em) return;
458
459 + pthread_mutex_lock(&lock);
460 + collect_pids &= ~(1<<EBPF_MODULE_DCSTAT_IDX);
461 + pthread_mutex_unlock(&lock);
462 +
463 if (ebpf_read_dcstat.thread)
464 nd_thread_signal_cancel(ebpf_read_dcstat.thread);
465
@@ -524,6 +528,9 @@ static void ebpf_dcstat_apps_accumulator(netdata_dcstat_pid_t *out, int maps_per
528
529 if (w->ct > ct)
530 ct = w->ct;
531 +
532 + if (!total->name[0] && w->name[0])
533 + strncpyz(total->name, w->name, sizeof(total->name) - 1);
534 }
535 total->ct = ct;
536 }
@@ -534,8 +541,9 @@ static void ebpf_dcstat_apps_accumulator(netdata_dcstat_pid_t *out, int maps_per
541 * Read the apps table and store data inside the structure.
542 *
543 * @param maps_per_core do I need to read all cores?
544 + * @param max_period limit of iterations without updates before remove data from hash table
545 */
538 -static void ebpf_read_dc_apps_table(int maps_per_core, int max_period)
546 +static void ebpf_read_dc_apps_table(int maps_per_core, uint32_t max_period)
547 {
548 netdata_dcstat_pid_t *cv = dcstat_vector;
549 int fd = dcstat_maps[NETDATA_DCSTAT_PID_STATS].map_fd;
@@ -551,16 +559,22 @@ static void ebpf_read_dc_apps_table(int maps_per_core, int max_period)
559
560 ebpf_dcstat_apps_accumulator(cv, maps_per_core);
561
554 - ebpf_pid_stat_t *pid_stat = ebpf_get_pid_entry(key, cv->tgid);
555 - if (pid_stat) {
556 - netdata_publish_dcstat_t *publish = &pid_stat->dc;
557 - if (!publish->ct || publish->ct != cv->ct) {
558 - memcpy(&publish->curr, &cv[0], sizeof(netdata_dcstat_pid_t));
559 - pid_stat->not_updated = 0;
560 - } else if (++pid_stat->not_updated >= max_period) {
561 - bpf_map_delete_elem(fd, &key);
562 - pid_stat->not_updated = 0;
563 - }
562 + ebpf_pid_data_t *pid_stat = ebpf_get_pid_data(key, cv->tgid, cv->name, EBPF_MODULE_DCSTAT_IDX);
563 + netdata_publish_dcstat_t *publish = pid_stat->dc;
564 + if (!publish)
565 + pid_stat->dc = publish = ebpf_dcallocate_publish();
566 +
567 + if (!publish->ct || publish->ct != cv->ct) {
568 + publish->ct = cv->ct;
569 + publish->curr.not_found = cv[0].not_found;
570 + publish->curr.file_system = cv[0].file_system;
571 + publish->curr.cache_access = cv[0].cache_access;
572 +
573 + pid_stat->not_updated = 0;
574 + } else if (++pid_stat->not_updated >= max_period) {
575 + ebpf_release_pid_data(pid_stat, fd, key, EBPF_MODULE_DCSTAT_IDX);
576 + ebpf_dc_release_publish(publish);
577 + pid_stat->dc = NULL;
578 }
579
580 end_dc_loop:
@@ -580,20 +594,17 @@ end_dc_loop:
594 */
595 void ebpf_dcstat_sum_pids(netdata_publish_dcstat_t *publish, struct ebpf_pid_on_target *root)
596 {
583 - memset(&publish->curr, 0, sizeof(netdata_dcstat_pid_t));
584 - netdata_dcstat_pid_t *dst = &publish->curr;
585 - while (root) {
597 + memset(&publish->curr, 0, sizeof(netdata_publish_dcstat_pid_t));
598 + for (; root; root = root->next) {
599 int32_t pid = root->pid;
587 - ebpf_pid_stat_t *pid_stat = ebpf_get_pid_entry(pid, 0);
588 - if (pid_stat) {
589 - netdata_publish_dcstat_t *w = &pid_stat->dc;
590 - netdata_dcstat_pid_t *src = &w->curr;
591 - dst->cache_access += src->cache_access;
592 - dst->file_system += src->file_system;
593 - dst->not_found += src->not_found;
594 - }
600 + ebpf_pid_data_t *pid_stat = ebpf_get_pid_data(pid, 0, NULL, EBPF_MODULE_DCSTAT_IDX);
601 + netdata_publish_dcstat_t *w = pid_stat->dc;
602 + if (!w)
603 + continue;
604
596 - root = root->next;
605 + publish->curr.cache_access += w->curr.cache_access;
606 + publish->curr.file_system += w->curr.file_system;
607 + publish->curr.not_found += w->curr.not_found;
608 }
609 }
610
@@ -635,13 +646,16 @@ void *ebpf_read_dcstat_thread(void *ptr)
646
647 int maps_per_core = em->maps_per_core;
648 int update_every = em->update_every;
649 + int collect_pid = (em->apps_charts || em->cgroup_charts);
650 + if (!collect_pid)
651 + return NULL;
652
653 int counter = update_every - 1;
654
655 uint32_t lifetime = em->lifetime;
656 uint32_t running_time = 0;
657 usec_t period = update_every * USEC_PER_SEC;
644 - int max_period = update_every * EBPF_CLEANUP_FACTOR;
658 + uint32_t max_period = EBPF_CLEANUP_FACTOR;
659 while (!ebpf_plugin_stop() && running_time < lifetime) {
660 (void)heartbeat_next(&hb, period);
661 if (ebpf_plugin_stop() || ++counter != update_every)
@@ -771,12 +785,12 @@ static void ebpf_update_dc_cgroup()
785 for (pids = ect->pids; pids; pids = pids->next) {
786 int pid = pids->pid;
787 netdata_dcstat_pid_t *out = &pids->dc;
774 - ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(pid, 0);
775 - if (local_pid) {
776 - netdata_publish_dcstat_t *in = &local_pid->dc;
788 + ebpf_pid_data_t *local_pid = ebpf_get_pid_data(pid, 0, NULL, EBPF_MODULE_DCSTAT_IDX);
789 + netdata_publish_dcstat_t *in = local_pid->dc;
790 + if (!in)
791 + continue;
792
778 - memcpy(out, &in->curr, sizeof(netdata_dcstat_pid_t));
779 - }
793 + memcpy(out, &in->curr, sizeof(netdata_publish_dcstat_pid_t));
794 }
795 }
796 pthread_mutex_unlock(&mutex_cgroup_shm);
@@ -1001,13 +1015,12 @@ static void ebpf_obsolete_specific_dc_charts(char *type, int update_every)
1015 void ebpf_dc_sum_cgroup_pids(netdata_publish_dcstat_t *publish, struct pid_on_target2 *root)
1016 {
1017 memset(&publish->curr, 0, sizeof(netdata_dcstat_pid_t));
1004 - netdata_dcstat_pid_t *dst = &publish->curr;
1018 while (root) {
1019 netdata_dcstat_pid_t *src = &root->dc;
1020
1008 - dst->cache_access += src->cache_access;
1009 - dst->file_system += src->file_system;
1010 - dst->not_found += src->not_found;
1021 + publish->curr.cache_access += src->cache_access;
1022 + publish->curr.file_system += src->file_system;
1023 + publish->curr.not_found += src->not_found;
1024
1025 root = root->next;
1026 }
src/collectors/ebpf.plugin/ebpf_dcstat.h
+15 -7
@@ -3,6 +3,8 @@
3 #ifndef NETDATA_EBPF_DCSTAT_H
4 #define NETDATA_EBPF_DCSTAT_H 1
5
6 +#include "ebpf.h"
7 +
8 // Module name & description
9 #define NETDATA_EBPF_MODULE_NAME_DCSTAT "dcstat"
10 #define NETDATA_EBPF_DC_MODULE_DESC "Monitor file access using directory cache. This thread is integrated with apps and cgroup."
@@ -69,26 +71,32 @@ enum directory_cache_targets {
71 NETDATA_DC_TARGET_D_LOOKUP
72 };
73
72 -typedef struct netdata_publish_dcstat_pid {
74 +typedef struct __attribute__((packed)) netdata_publish_dcstat_pid {
75 + uint64_t cache_access;
76 + uint32_t file_system;
77 + uint32_t not_found;
78 +} netdata_publish_dcstat_pid_t;
79 +
80 +typedef struct netdata_dcstat_pid {
81 uint64_t ct;
82 uint32_t tgid;
83 uint32_t uid;
84 uint32_t gid;
85 char name[TASK_COMM_LEN];
86
79 - uint64_t cache_access;
80 - uint64_t file_system;
81 - uint64_t not_found;
87 + uint32_t cache_access;
88 + uint32_t file_system;
89 + uint32_t not_found;
90 } netdata_dcstat_pid_t;
91
84 -typedef struct netdata_publish_dcstat {
92 +typedef struct __attribute__((packed)) netdata_publish_dcstat {
93 uint64_t ct;
94
95 long long ratio;
96 long long cache_access;
97
90 - netdata_dcstat_pid_t curr;
91 - netdata_dcstat_pid_t prev;
98 + netdata_publish_dcstat_pid_t curr;
99 + netdata_publish_dcstat_pid_t prev;
100 } netdata_publish_dcstat_t;
101
102 void *ebpf_dcstat_thread(void *ptr);
src/collectors/ebpf.plugin/ebpf_fd.c
+55 -34
@@ -551,6 +551,10 @@ static void ebpf_fd_exit(void *pptr)
551 ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
552 if(!em) return;
553
554 + pthread_mutex_lock(&lock);
555 + collect_pids &= ~(1<<EBPF_MODULE_FD_IDX);
556 + pthread_mutex_unlock(&lock);
557 +
558 if (ebpf_read_fd.thread)
559 nd_thread_signal_cancel(ebpf_read_fd.thread);
560
@@ -656,12 +660,19 @@ static void fd_apps_accumulator(netdata_fd_stat_t *out, int maps_per_core)
660 {
661 int i, end = (maps_per_core) ? ebpf_nprocs : 1;
662 netdata_fd_stat_t *total = &out[0];
663 + uint64_t ct = total->ct;
664 for (i = 1; i < end; i++) {
665 netdata_fd_stat_t *w = &out[i];
666 total->open_call += w->open_call;
667 total->close_call += w->close_call;
668 total->open_err += w->open_err;
669 total->close_err += w->close_err;
670 +
671 + if (w->ct > ct)
672 + ct = w->ct;
673 +
674 + if (!total->name[0] && w->name[0])
675 + strncpyz(total->name, w->name, sizeof(total->name) - 1);
676 }
677 }
678
@@ -671,8 +682,9 @@ static void fd_apps_accumulator(netdata_fd_stat_t *out, int maps_per_core)
682 * Read the apps table and store data inside the structure.
683 *
684 * @param maps_per_core do I need to read all cores?
685 + * @param max_period limit of iterations without updates before remove data from hash table
686 */
675 -static void ebpf_read_fd_apps_table(int maps_per_core, int max_period)
687 +static void ebpf_read_fd_apps_table(int maps_per_core, uint32_t max_period)
688 {
689 netdata_fd_stat_t *fv = fd_vector;
690 int fd = fd_maps[NETDATA_FD_PID_STATS].map_fd;
@@ -688,16 +700,23 @@ static void ebpf_read_fd_apps_table(int maps_per_core, int max_period)
700
701 fd_apps_accumulator(fv, maps_per_core);
702
691 - ebpf_pid_stat_t *pid_stat = ebpf_get_pid_entry(key, fv->tgid);
692 - if (pid_stat) {
693 - netdata_fd_stat_t *publish_fd = &pid_stat->fd;
694 - if (!publish_fd->ct || publish_fd->ct != fv->ct) {
695 - memcpy(publish_fd, &fv[0], sizeof(netdata_fd_stat_t));
696 - pid_stat->not_updated = 0;
697 - } else if (++pid_stat->not_updated >= max_period) {
698 - bpf_map_delete_elem(fd, &key);
699 - pid_stat->not_updated = 0;
700 - }
703 + ebpf_pid_data_t *pid_stat = ebpf_get_pid_data(key, fv->tgid, fv->name, EBPF_MODULE_FD_IDX);
704 + netdata_publish_fd_stat_t *publish_fd = pid_stat->fd;
705 + if (!publish_fd)
706 + pid_stat->fd = publish_fd = ebpf_fd_allocate_publish();
707 +
708 + if (!publish_fd->ct || publish_fd->ct != fv->ct) {
709 + publish_fd->ct = fv->ct;
710 + publish_fd->open_call = fv->open_call;
711 + publish_fd->close_call = fv->close_call;
712 + publish_fd->open_err = fv->open_err;
713 + publish_fd->close_err = fv->close_err;
714 +
715 + pid_stat->not_updated = 0;
716 + } else if (++pid_stat->not_updated >= max_period) {
717 + ebpf_release_pid_data(pid_stat, fd, key, EBPF_MODULE_FD_IDX);
718 + ebpf_fd_release_publish(publish_fd);
719 + pid_stat->fd = NULL;
720 }
721
722 end_fd_loop:
@@ -719,18 +738,17 @@ static void ebpf_fd_sum_pids(netdata_fd_stat_t *fd, struct ebpf_pid_on_target *r
738 {
739 memset(fd, 0, sizeof(netdata_fd_stat_t));
740
722 - while (root) {
741 + for (; root; root = root->next) {
742 int32_t pid = root->pid;
724 - ebpf_pid_stat_t *pid_stat = ebpf_get_pid_entry(pid, 0);
725 - if (pid_stat) {
726 - netdata_fd_stat_t *w = &pid_stat->fd;
727 - fd->open_call += w->open_call;
728 - fd->close_call += w->close_call;
729 - fd->open_err += w->open_err;
730 - fd->close_err += w->close_err;
731 - }
743 + ebpf_pid_data_t *pid_stat = ebpf_get_pid_data(pid, 0, NULL, EBPF_MODULE_FD_IDX);
744 + netdata_publish_fd_stat_t *w = pid_stat->fd;
745 + if (!w)
746 + continue;
747
733 - root = root->next;
748 + fd->open_call += w->open_call;
749 + fd->close_call += w->close_call;
750 + fd->open_err += w->open_err;
751 + fd->close_err += w->close_err;
752 }
753 }
754
@@ -767,13 +785,16 @@ void *ebpf_read_fd_thread(void *ptr)
785
786 int maps_per_core = em->maps_per_core;
787 int update_every = em->update_every;
788 + int collect_pid = (em->apps_charts || em->cgroup_charts);
789 + if (!collect_pid)
790 + return NULL;
791
792 int counter = update_every - 1;
793
794 uint32_t lifetime = em->lifetime;
795 uint32_t running_time = 0;
775 - usec_t period = update_every * USEC_PER_SEC;
776 - int max_period = update_every * EBPF_CLEANUP_FACTOR;
796 + int period = USEC_PER_SEC;
797 + uint32_t max_period = EBPF_CLEANUP_FACTOR;
798 while (!ebpf_plugin_stop() && running_time < lifetime) {
799 (void)heartbeat_next(&hb, period);
800 if (ebpf_plugin_stop() || ++counter != update_every)
@@ -815,13 +836,12 @@ static void ebpf_update_fd_cgroup()
836 struct pid_on_target2 *pids;
837 for (pids = ect->pids; pids; pids = pids->next) {
838 int pid = pids->pid;
818 - netdata_fd_stat_t *out = &pids->fd;
819 - ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(pid, 0);
820 - if (local_pid) {
821 - netdata_fd_stat_t *in = &local_pid->fd;
822 -
823 - memcpy(out, in, sizeof(netdata_fd_stat_t));
824 - }
839 + netdata_publish_fd_stat_t *out = &pids->fd;
840 + ebpf_pid_data_t *local_pid = ebpf_get_pid_data(pid, 0, NULL, EBPF_MODULE_FD_IDX);
841 + netdata_publish_fd_stat_t *in = local_pid->fd;
842 + if (!in)
843 + continue;
844 + memcpy(out, in, sizeof(netdata_publish_fd_stat_t));
845 }
846 }
847 pthread_mutex_unlock(&mutex_cgroup_shm);
@@ -872,13 +892,13 @@ void ebpf_fd_send_apps_data(ebpf_module_t *em, struct ebpf_target *root)
892 * @param fd structure used to store data
893 * @param pids input data
894 */
875 -static void ebpf_fd_sum_cgroup_pids(netdata_fd_stat_t *fd, struct pid_on_target2 *pids)
895 +static void ebpf_fd_sum_cgroup_pids(netdata_publish_fd_stat_t *fd, struct pid_on_target2 *pids)
896 {
897 netdata_fd_stat_t accumulator;
898 memset(&accumulator, 0, sizeof(accumulator));
899
900 while (pids) {
881 - netdata_fd_stat_t *w = &pids->fd;
901 + netdata_publish_fd_stat_t *w = &pids->fd;
902
903 accumulator.open_err += w->open_err;
904 accumulator.open_call += w->open_call;
@@ -995,7 +1015,7 @@ static void ebpf_obsolete_specific_fd_charts(char *type, ebpf_module_t *em)
1015 * @param type chart type
1016 * @param values structure with values that will be sent to netdata
1017 */
998 -static void ebpf_send_specific_fd_data(char *type, netdata_fd_stat_t *values, ebpf_module_t *em)
1018 +static void ebpf_send_specific_fd_data(char *type, netdata_publish_fd_stat_t *values, ebpf_module_t *em)
1019 {
1020 ebpf_write_begin_chart(type, NETDATA_SYSCALL_APPS_FILE_OPEN, "");
1021 write_chart_dimension(fd_publish_aggregated[NETDATA_FD_SYSCALL_OPEN].name, (long long)values->open_call);
@@ -1463,7 +1483,8 @@ void *ebpf_fd_thread(void *ptr)
1483
1484 pthread_mutex_unlock(&lock);
1485
1466 - ebpf_read_fd.thread = nd_thread_create(ebpf_read_fd.name, NETDATA_THREAD_OPTION_DEFAULT, ebpf_read_fd_thread, em);
1486 + ebpf_read_fd.thread = nd_thread_create(ebpf_read_fd.name, NETDATA_THREAD_OPTION_DEFAULT,
1487 + ebpf_read_fd_thread, em);
1488
1489 fd_collector(em);
1490
src/collectors/ebpf.plugin/ebpf_fd.h
+11
@@ -40,6 +40,17 @@
40 // ARAL name
41 #define NETDATA_EBPF_FD_ARAL_NAME "ebpf_fd"
42
43 +typedef struct __attribute__((packed)) netdata_publish_fd_stat {
44 + uint64_t ct;
45 +
46 + uint32_t open_call; // Open syscalls (open and openat)
47 + uint32_t close_call; // Close syscall (close)
48 +
49 + // Errors
50 + uint32_t open_err;
51 + uint32_t close_err;
52 +} netdata_publish_fd_stat_t;
53 +
54 typedef struct netdata_fd_stat {
55 uint64_t ct;
56 uint32_t tgid;
src/collectors/ebpf.plugin/ebpf_filesystem.c
+55 -8
@@ -333,6 +333,46 @@ static inline int ebpf_fs_load_and_attach(ebpf_local_maps_t *map, struct filesys
333 *
334 *****************************************************************/
335
336 +/**
337 + * Obsolete Cleanup Struct
338 + *
339 + * Clean allocatged data durinc obsolete steps
340 + *
341 + * @param efp
342 + */
343 +static void ebpf_obsolete_cleanup_struct(ebpf_filesystem_partitions_t *efp) {
344 + freez(efp->hread.name);
345 + efp->hread.name = NULL;
346 + freez(efp->hread.title);
347 + efp->hread.title = NULL;
348 + freez(efp->hread.ctx);
349 + efp->hread.ctx = NULL;
350 +
351 + freez(efp->hwrite.name);
352 + efp->hwrite.name = NULL;
353 + freez(efp->hwrite.title);
354 + efp->hwrite.title = NULL;
355 + freez(efp->hwrite.ctx);
356 + efp->hwrite.ctx = NULL;
357 +
358 + freez(efp->hopen.name);
359 + efp->hopen.name = NULL;
360 + freez(efp->hopen.title);
361 + efp->hopen.title = NULL;
362 + freez(efp->hopen.ctx);
363 + efp->hopen.ctx = NULL;
364 +
365 + freez(efp->hadditional.name);
366 + efp->hadditional.name = NULL;
367 + freez(efp->hadditional.title);
368 + efp->hadditional.title = NULL;
369 + freez(efp->hadditional.ctx);
370 + efp->hadditional.ctx = NULL;
371 +
372 + freez(efp->family_name);
373 + efp->family_name = NULL;
374 +}
375 +
376 /**
377 * Create Filesystem chart
378 *
@@ -348,7 +388,7 @@ static void ebpf_obsolete_fs_charts(int update_every)
388 ebpf_filesystem_partitions_t *efp = &localfs[i];
389 uint32_t flags = efp->flags;
390 if ((flags & test) == test) {
351 - flags &= ~NETDATA_FILESYSTEM_FLAG_CHART_CREATED;
391 + flags &= ~test;
392
393 ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY, efp->hread.name,
394 "",
@@ -370,6 +410,8 @@ static void ebpf_obsolete_fs_charts(int update_every)
410 EBPF_COMMON_UNITS_CALLS_PER_SEC, efp->family_name,
411 NULL, NETDATA_EBPF_CHART_TYPE_STACKED, efp->hadditional.order,
412 update_every);
413 +
414 + ebpf_obsolete_cleanup_struct(efp);
415 }
416 efp->flags = flags;
417 }
@@ -395,9 +437,10 @@ static void ebpf_create_fs_charts(int update_every)
437 snprintfz(title, sizeof(title) - 1, "%s latency for each read request.", efp->filesystem);
438 snprintfz(family, sizeof(family) - 1, "%s_latency", efp->family);
439 snprintfz(chart_name, sizeof(chart_name) - 1, "%s_read_latency", efp->filesystem);
440 + snprintfz(ctx, sizeof(ctx) - 1, "filesystem.read_latency");
441 efp->hread.name = strdupz(chart_name);
442 efp->hread.title = strdupz(title);
400 - efp->hread.ctx = NULL;
443 + efp->hread.ctx = strdupz(ctx);
444 efp->hread.order = order;
445 efp->family_name = strdupz(family);
446
@@ -412,9 +455,10 @@ static void ebpf_create_fs_charts(int update_every)
455
456 snprintfz(title, sizeof(title) - 1, "%s latency for each write request.", efp->filesystem);
457 snprintfz(chart_name, sizeof(chart_name) - 1, "%s_write_latency", efp->filesystem);
458 + snprintfz(ctx, sizeof(ctx) - 1, "filesystem.write_latency");
459 efp->hwrite.name = strdupz(chart_name);
460 efp->hwrite.title = strdupz(title);
417 - efp->hwrite.ctx = NULL;
461 + efp->hwrite.ctx = strdupz(ctx);
462 efp->hwrite.order = order;
463 ebpf_create_chart(NETDATA_FILESYSTEM_FAMILY, efp->hwrite.name,
464 efp->hwrite.title,
@@ -427,9 +471,10 @@ static void ebpf_create_fs_charts(int update_every)
471
472 snprintfz(title, sizeof(title) - 1, "%s latency for each open request.", efp->filesystem);
473 snprintfz(chart_name, sizeof(chart_name) - 1, "%s_open_latency", efp->filesystem);
474 + snprintfz(ctx, sizeof(ctx) - 1, "filesystem.open_latency");
475 efp->hopen.name = strdupz(chart_name);
476 efp->hopen.title = strdupz(title);
432 - efp->hopen.ctx = NULL;
477 + efp->hopen.ctx = strdupz(ctx);
478 efp->hopen.order = order;
479 ebpf_create_chart(NETDATA_FILESYSTEM_FAMILY, efp->hopen.name,
480 efp->hopen.title,
@@ -443,7 +488,7 @@ static void ebpf_create_fs_charts(int update_every)
488 char *type = (efp->flags & NETDATA_FILESYSTEM_ATTR_CHARTS) ? "attribute" : "sync";
489 snprintfz(title, sizeof(title) - 1, "%s latency for each %s request.", efp->filesystem, type);
490 snprintfz(chart_name, sizeof(chart_name) - 1, "%s_%s_latency", efp->filesystem, type);
446 - snprintfz(ctx, sizeof(ctx) - 1, "filesystem.%s_latency", type);
491 + snprintfz(ctx, sizeof(ctx) - 1, "filesystem.%s_latency", efp->filesystem);
492 efp->hadditional.name = strdupz(chart_name);
493 efp->hadditional.title = strdupz(title);
494 efp->hadditional.ctx = strdupz(ctx);
@@ -575,7 +620,9 @@ static int ebpf_read_local_partitions()
620 ebpf_filesystem_partitions_t *w = &localfs[i];
621 if (w->enabled && (!strcmp(fs, w->filesystem) ||
622 (w->optional_filesystem && !strcmp(fs, w->optional_filesystem)))) {
578 - localfs[i].flags |= NETDATA_FILESYSTEM_LOAD_EBPF_PROGRAM;
623 + if (!(localfs[i].flags & NETDATA_FILESYSTEM_FLAG_CHART_CREATED))
624 + localfs[i].flags |= NETDATA_FILESYSTEM_LOAD_EBPF_PROGRAM;
625 +
626 localfs[i].flags &= ~NETDATA_FILESYSTEM_REMOVE_CHARTS;
627 count++;
628 break;
@@ -892,10 +939,10 @@ static void read_filesystem_tables(int maps_per_core)
939 */
940 void ebpf_filesystem_read_hash(ebpf_module_t *em)
941 {
895 - ebpf_obsolete_fs_charts(em->update_every);
896 -
942 (void) ebpf_update_partitions(em);
943
944 + ebpf_obsolete_fs_charts(em->update_every);
945 +
946 if (em->optional)
947 return;
948
src/collectors/ebpf.plugin/ebpf_functions.c
+2 -1
@@ -331,7 +331,7 @@ static void ebpf_function_socket_manipulation(const char *transaction,
331 "Filters can be combined. Each filter can be given only one time. Default all ports\n"
332 };
333
334 -for (int i = 1; i < PLUGINSD_MAX_WORDS; i++) {
334 + for (int i = 1; i < PLUGINSD_MAX_WORDS; i++) {
335 const char *keyword = get_word(words, num_words, i);
336 if (!keyword)
337 break;
@@ -428,6 +428,7 @@ for (int i = 1; i < PLUGINSD_MAX_WORDS; i++) {
428 ebpf_socket_clean_judy_array_unsafe();
429 rw_spinlock_write_unlock(&ebpf_judy_pid.index.rw_spinlock);
430
431 + collect_pids |= 1<<EBPF_MODULE_SOCKET_IDX;
432 pthread_mutex_lock(&ebpf_exit_cleanup);
433 if (ebpf_function_start_thread(em, period)) {
434 ebpf_function_error(transaction,
src/collectors/ebpf.plugin/ebpf_oomkill.c
+5 -1
@@ -133,6 +133,10 @@ static void oomkill_cleanup(void *pptr)
133 ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
134 if(!em) return;
135
136 + pthread_mutex_lock(&lock);
137 + collect_pids &= ~(1<<EBPF_MODULE_OOMKILL_IDX);
138 + pthread_mutex_unlock(&lock);
139 +
140 if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
141 pthread_mutex_lock(&lock);
142
@@ -549,7 +553,7 @@ void *ebpf_oomkill_thread(void *ptr)
553 em->maps = oomkill_maps;
554
555 #define NETDATA_DEFAULT_OOM_DISABLED_MSG "Disabling OOMKILL thread, because"
552 - if (unlikely(!ebpf_all_pids || !em->apps_charts)) {
556 + if (unlikely(!em->apps_charts)) {
557 // When we are not running integration with apps, we won't fill necessary variables for this thread to run, so
558 // we need to disable it.
559 pthread_mutex_lock(&ebpf_exit_cleanup);
src/collectors/ebpf.plugin/ebpf_process.c
+14 -10
@@ -229,13 +229,13 @@ static void ebpf_update_process_cgroup()
229 struct pid_on_target2 *pids;
230 for (pids = ect->pids; pids; pids = pids->next) {
231 int pid = pids->pid;
232 - ebpf_process_stat_t *out = &pids->ps;
233 - ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(pid, 0);
234 - if (local_pid) {
235 - ebpf_process_stat_t *in = &local_pid->process;
232 + ebpf_publish_process_t *out = &pids->ps;
233 + ebpf_pid_data_t *local_pid = ebpf_get_pid_data(pid, 0, NULL, EBPF_MODULE_PROCESS_IDX);
234 + ebpf_publish_process_t *in = local_pid->process;
235 + if (!in)
236 + continue;
237
237 - memcpy(out, in, sizeof(ebpf_process_stat_t));
238 - }
238 + memcpy(out, in, sizeof(ebpf_publish_process_t));
239 }
240 }
241 pthread_mutex_unlock(&mutex_cgroup_shm);
@@ -694,6 +694,10 @@ static void ebpf_process_exit(void *pptr)
694 ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
695 if(!em) return;
696
697 + pthread_mutex_lock(&lock);
698 + collect_pids &= ~(1<<EBPF_MODULE_PROCESS_IDX);
699 + pthread_mutex_unlock(&lock);
700 +
701 if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
702 pthread_mutex_lock(&lock);
703 if (em->cgroup_charts) {
@@ -746,13 +750,13 @@ static void ebpf_process_exit(void *pptr)
750 * @param ps structure used to store data
751 * @param pids input data
752 */
749 -static void ebpf_process_sum_cgroup_pids(ebpf_process_stat_t *ps, struct pid_on_target2 *pids)
753 +static void ebpf_process_sum_cgroup_pids(ebpf_publish_process_t *ps, struct pid_on_target2 *pids)
754 {
751 - ebpf_process_stat_t accumulator;
755 + ebpf_publish_process_t accumulator;
756 memset(&accumulator, 0, sizeof(accumulator));
757
758 while (pids) {
755 - ebpf_process_stat_t *pps = &pids->ps;
759 + ebpf_publish_process_t *pps = &pids->ps;
760
761 accumulator.exit_call += pps->exit_call;
762 accumulator.release_call += pps->release_call;
@@ -781,7 +785,7 @@ static void ebpf_process_sum_cgroup_pids(ebpf_process_stat_t *ps, struct pid_on_
785 * @param values structure with values that will be sent to netdata
786 * @param em the structure with thread information
787 */
784 -static void ebpf_send_specific_process_data(char *type, ebpf_process_stat_t *values, ebpf_module_t *em)
788 +static void ebpf_send_specific_process_data(char *type, ebpf_publish_process_t *values, ebpf_module_t *em)
789 {
790 ebpf_write_begin_chart(type, NETDATA_SYSCALL_APPS_TASK_PROCESS, "");
791 write_chart_dimension(process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_FORK].name,
src/collectors/ebpf.plugin/ebpf_process.h
+1
@@ -43,6 +43,7 @@
43
44 enum netdata_ebpf_stats_order {
45 NETDATA_EBPF_ORDER_STAT_THREADS = 140000,
46 + NETDATA_EBPF_ORDER_PIDS,
47 NETDATA_EBPF_ORDER_STAT_LIFE_TIME,
48 NETDATA_EBPF_ORDER_STAT_LOAD_METHOD,
49 NETDATA_EBPF_ORDER_STAT_KERNEL_MEMORY,
src/collectors/ebpf.plugin/ebpf_shm.c
+48 -38
@@ -7,7 +7,7 @@ static char *shm_dimension_name[NETDATA_SHM_END] = { "get", "at", "dt", "ctl" };
7 static netdata_syscall_stat_t shm_aggregated_data[NETDATA_SHM_END];
8 static netdata_publish_syscall_t shm_publish_aggregated[NETDATA_SHM_END];
9
10 -netdata_publish_shm_t *shm_vector = NULL;
10 +netdata_ebpf_shm_t *shm_vector = NULL;
11
12 static netdata_idx_t shm_hash_values[NETDATA_SHM_END];
13 static netdata_idx_t *shm_values = NULL;
@@ -453,6 +453,10 @@ static void ebpf_shm_exit(void *pptr)
453 ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
454 if(!em) return;
455
456 + pthread_mutex_lock(&lock);
457 + collect_pids &= ~(1<<EBPF_MODULE_SHM_IDX);
458 + pthread_mutex_unlock(&lock);
459 +
460 if (ebpf_read_shm.thread)
461 nd_thread_signal_cancel(ebpf_read_shm.thread);
462
@@ -506,16 +510,23 @@ static void ebpf_shm_exit(void *pptr)
510 * @param out the vector with read values.
511 * @param maps_per_core do I need to read all cores?
512 */
509 -static void shm_apps_accumulator(netdata_publish_shm_t *out, int maps_per_core)
513 +static void shm_apps_accumulator(netdata_ebpf_shm_t *out, int maps_per_core)
514 {
515 int i, end = (maps_per_core) ? ebpf_nprocs : 1;
512 - netdata_publish_shm_t *total = &out[0];
516 + netdata_ebpf_shm_t *total = &out[0];
517 + uint64_t ct = total->ct;
518 for (i = 1; i < end; i++) {
514 - netdata_publish_shm_t *w = &out[i];
519 + netdata_ebpf_shm_t *w = &out[i];
520 total->get += w->get;
521 total->at += w->at;
522 total->dt += w->dt;
523 total->ctl += w->ctl;
524 +
525 + if (w->ct > ct)
526 + ct = w->ct;
527 +
528 + if (!total->name[0] && w->name[0])
529 + strncpyz(total->name, w->name, sizeof(total->name) - 1);
530 }
531 }
532
@@ -528,7 +539,7 @@ static void shm_apps_accumulator(netdata_publish_shm_t *out, int maps_per_core)
539 */
540 static void ebpf_update_shm_cgroup()
541 {
531 - netdata_publish_shm_t *cv = shm_vector;
542 + netdata_ebpf_shm_t *cv = shm_vector;
543 size_t length = sizeof(netdata_publish_shm_t);
544
545 ebpf_cgroup_target_t *ect;
@@ -541,12 +552,12 @@ static void ebpf_update_shm_cgroup()
552 for (pids = ect->pids; pids; pids = pids->next) {
553 int pid = pids->pid;
554 netdata_publish_shm_t *out = &pids->shm;
544 - ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(pid, 0);
545 - if (local_pid) {
546 - netdata_publish_shm_t *in = &local_pid->shm;
555 + ebpf_pid_data_t *local_pid = ebpf_get_pid_data(pid, 0, NULL, EBPF_MODULE_SHM_IDX);
556 + netdata_publish_shm_t *in = local_pid->shm;
557 + if (!in)
558 + continue;
559
548 - memcpy(out, in, sizeof(netdata_publish_shm_t));
549 - }
560 + memcpy(out, in, sizeof(netdata_publish_shm_t));
561 }
562 }
563 pthread_mutex_unlock(&mutex_cgroup_shm);
@@ -558,12 +569,13 @@ static void ebpf_update_shm_cgroup()
569 * Read the apps table and store data inside the structure.
570 *
571 * @param maps_per_core do I need to read all cores?
572 + * @param max_period limit of iterations without updates before remove data from hash table
573 */
562 -static void ebpf_read_shm_apps_table(int maps_per_core, int max_period)
574 +static void ebpf_read_shm_apps_table(int maps_per_core, uint32_t max_period)
575 {
564 - netdata_publish_shm_t *cv = shm_vector;
576 + netdata_ebpf_shm_t *cv = shm_vector;
577 int fd = shm_maps[NETDATA_PID_SHM_TABLE].map_fd;
566 - size_t length = sizeof(netdata_publish_shm_t);
578 + size_t length = sizeof(netdata_ebpf_shm_t);
579 if (maps_per_core)
580 length *= ebpf_nprocs;
581
@@ -575,18 +587,18 @@ static void ebpf_read_shm_apps_table(int maps_per_core, int max_period)
587
588 shm_apps_accumulator(cv, maps_per_core);
589
578 - ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(key, 0);
579 - if (!local_pid)
580 - goto end_shm_loop;
590 + ebpf_pid_data_t *local_pid = ebpf_get_pid_data(key, cv->tgid, cv->name, EBPF_MODULE_SHM_IDX);
591 + netdata_publish_shm_t *publish = local_pid->shm;
592 + if (!publish)
593 + local_pid->shm = publish = ebpf_shm_allocate_publish();
594
582 -
583 - netdata_publish_shm_t *publish = &local_pid->shm;
595 if (!publish->ct || publish->ct != cv->ct) {
596 memcpy(publish, &cv[0], sizeof(netdata_publish_shm_t));
597 local_pid->not_updated = 0;
598 } else if (++local_pid->not_updated >= max_period){
588 - bpf_map_delete_elem(fd, &key);
589 - local_pid->not_updated = 0;
599 + ebpf_release_pid_data(local_pid, fd, key, EBPF_MODULE_SHM_IDX);
600 + ebpf_shm_release_publish(publish);
601 + local_pid->shm = NULL;
602 }
603
604 end_shm_loop:
@@ -654,23 +666,17 @@ static void ebpf_shm_read_global_table(netdata_idx_t *stats, int maps_per_core)
666 static void ebpf_shm_sum_pids(netdata_publish_shm_t *shm, struct ebpf_pid_on_target *root)
667 {
668 memset(shm, 0, sizeof(netdata_publish_shm_t));
657 - while (root) {
669 + for (; root; root = root->next) {
670 int32_t pid = root->pid;
659 - ebpf_pid_stat_t *pid_stat = ebpf_get_pid_entry(pid, 0);
660 - if (pid_stat) {
661 - netdata_publish_shm_t *w = &pid_stat->shm;
662 - shm->get += w->get;
663 - shm->at += w->at;
664 - shm->dt += w->dt;
665 - shm->ctl += w->ctl;
666 -
667 - // reset for next collection.
668 - w->get = 0;
669 - w->at = 0;
670 - w->dt = 0;
671 - w->ctl = 0;
672 - }
673 - root = root->next;
671 + ebpf_pid_data_t *pid_stat = ebpf_get_pid_data(pid, 0, NULL, EBPF_MODULE_SHM_IDX);
672 + netdata_publish_shm_t *w = pid_stat->shm;
673 + if (!w)
674 + continue;
675 +
676 + shm->get += w->get;
677 + shm->at += w->at;
678 + shm->dt += w->dt;
679 + shm->ctl += w->ctl;
680 }
681 }
682
@@ -1060,13 +1066,16 @@ void *ebpf_read_shm_thread(void *ptr)
1066
1067 int maps_per_core = em->maps_per_core;
1068 int update_every = em->update_every;
1069 + int collect_pid = (em->apps_charts || em->cgroup_charts);
1070 + if (!collect_pid)
1071 + return NULL;
1072
1073 int counter = update_every - 1;
1074
1075 uint32_t lifetime = em->lifetime;
1076 uint32_t running_time = 0;
1077 usec_t period = update_every * USEC_PER_SEC;
1069 - int max_period = update_every * EBPF_CLEANUP_FACTOR;
1078 + uint32_t max_period = EBPF_CLEANUP_FACTOR;
1079 while (!ebpf_plugin_stop() && running_time < lifetime) {
1080 (void)heartbeat_next(&hb, period);
1081 if (ebpf_plugin_stop() || ++counter != update_every)
@@ -1363,7 +1372,8 @@ void *ebpf_shm_thread(void *ptr)
1372 ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_ADD);
1373 pthread_mutex_unlock(&lock);
1374
1366 - ebpf_read_shm.thread = nd_thread_create(ebpf_read_shm.name, NETDATA_THREAD_OPTION_DEFAULT, ebpf_read_shm_thread, em);
1375 + ebpf_read_shm.thread = nd_thread_create(ebpf_read_shm.name, NETDATA_THREAD_OPTION_DEFAULT,
1376 + ebpf_read_shm_thread, em);
1377
1378 shm_collector(em);
1379
src/collectors/ebpf.plugin/ebpf_shm.h
+18 -6
@@ -28,16 +28,28 @@
28 #define NETDATA_SYSTEMD_SHM_DT_CONTEXT "systemd.service.shmdt"
29 #define NETDATA_SYSTEMD_SHM_CTL_CONTEXT "systemd.service.shmctl"
30
31 -typedef struct netdata_publish_shm {
31 +typedef struct __attribute__((packed)) netdata_publish_shm {
32 uint64_t ct;
33 - char name[TASK_COMM_LEN];
33
35 - uint64_t get;
36 - uint64_t at;
37 - uint64_t dt;
38 - uint64_t ctl;
34 + uint32_t get;
35 + uint32_t at;
36 + uint32_t dt;
37 + uint32_t ctl;
38 } netdata_publish_shm_t;
39
40 +typedef struct netdata_ebpf_shm {
41 + uint64_t ct;
42 + uint32_t tgid;
43 + uint32_t uid;
44 + uint32_t gid;
45 + char name[TASK_COMM_LEN];
46 +
47 + uint32_t get;
48 + uint32_t at;
49 + uint32_t dt;
50 + uint32_t ctl;
51 +} netdata_ebpf_shm_t;
52 +
53 enum shm_tables {
54 NETDATA_PID_SHM_TABLE,
55 NETDATA_SHM_CONTROLLER,
src/collectors/ebpf.plugin/ebpf_socket.c
+57 -42
@@ -497,6 +497,10 @@ static void ebpf_socket_free(ebpf_module_t *em )
497 ebpf_update_stats(&plugin_statistics, em);
498 ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_REMOVE);
499 pthread_mutex_unlock(&ebpf_exit_cleanup);
500 +
501 + pthread_mutex_lock(&lock);
502 + collect_pids &= ~(1<<EBPF_MODULE_SOCKET_IDX);
503 + pthread_mutex_unlock(&lock);
504 }
505
506 /**
@@ -1674,6 +1678,7 @@ static void ebpf_update_array_vectors(ebpf_module_t *em)
1678 time_t update_time = time(NULL);
1679 while (bpf_map_get_next_key(fd, &key, &next_key) == 0) {
1680 test = bpf_map_lookup_elem(fd, &key, values);
1681 + bool deleted = true;
1682 if (test < 0) {
1683 goto end_socket_loop;
1684 }
@@ -1683,7 +1688,6 @@ static void ebpf_update_array_vectors(ebpf_module_t *em)
1688 }
1689
1690 ebpf_hash_socket_accumulator(values, end);
1686 - ebpf_socket_fill_publish_apps(key.pid, values);
1691
1692 // We update UDP to show info with charts, but we do not show them with functions
1693 /*
@@ -1727,14 +1731,17 @@ static void ebpf_update_array_vectors(ebpf_module_t *em)
1731 }
1732 uint64_t prev_period = socket_ptr->data.current_timestamp;
1733 memcpy(&socket_ptr->data, &values[0], sizeof(netdata_socket_t));
1730 - if (translate)
1734 + if (translate) {
1735 ebpf_socket_translate(socket_ptr, &key);
1732 - else { // Check socket was updated
1736 + deleted = false;
1737 + } else { // Check socket was updated
1738 + deleted = false;
1739 if (prev_period) {
1740 if (values[0].current_timestamp > prev_period) // Socket updated
1741 socket_ptr->last_update = update_time;
1742 else if ((update_time - socket_ptr->last_update) > em->update_every) {
1743 // Socket was not updated since last read
1744 + deleted = true;
1745 JudyLDel(&pid_ptr->socket_stats.JudyLArray, values[0].first_timestamp, PJE0);
1746 aral_freez(aral_socket_table, socket_ptr);
1747 }
@@ -1745,7 +1752,19 @@ static void ebpf_update_array_vectors(ebpf_module_t *em)
1752 rw_spinlock_write_unlock(&pid_ptr->socket_stats.rw_spinlock);
1753 rw_spinlock_write_unlock(&ebpf_judy_pid.index.rw_spinlock);
1754
1748 -end_socket_loop:
1755 +end_socket_loop: ; // the empty statement is here to allow code to be compiled by old compilers
1756 + ebpf_pid_data_t *local_pid = ebpf_get_pid_data(key.pid, 0, values[0].name, EBPF_MODULE_SOCKET_IDX);
1757 + ebpf_socket_publish_apps_t *curr = local_pid->socket;
1758 + if (!curr)
1759 + local_pid->socket = curr = ebpf_socket_allocate_publish();
1760 +
1761 + if (!deleted)
1762 + ebpf_socket_fill_publish_apps(curr, values);
1763 + else {
1764 + ebpf_release_pid_data(local_pid, fd, key.pid, EBPF_MODULE_SOCKET_IDX);
1765 + ebpf_socket_release_publish(curr);
1766 + local_pid->socket = NULL;
1767 + }
1768 memset(values, 0, length);
1769 memcpy(&key, &next_key, sizeof(key));
1770 }
@@ -1765,23 +1784,22 @@ void ebpf_socket_resume_apps_data()
1784
1785 ebpf_socket_publish_apps_t *values = &w->socket;
1786 memset(&w->socket, 0, sizeof(ebpf_socket_publish_apps_t));
1768 - while (move) {
1787 + for (; move; move = move->next) {
1788 int32_t pid = move->pid;
1770 - ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(pid, 0);
1771 - if (local_pid) {
1772 - ebpf_socket_publish_apps_t *ws = &local_pid->socket;
1773 - values->call_tcp_v4_connection = ws->call_tcp_v4_connection;
1774 - values->call_tcp_v6_connection = ws->call_tcp_v6_connection;
1775 - values->bytes_sent = ws->bytes_sent;
1776 - values->bytes_received = ws->bytes_received;
1777 - values->call_tcp_sent = ws->call_tcp_sent;
1778 - values->call_tcp_received = ws->call_tcp_received;
1779 - values->retransmit = ws->retransmit;
1780 - values->call_udp_sent = ws->call_udp_sent;
1781 - values->call_udp_received = ws->call_udp_received;
1782 - }
1783 -
1784 - move = move->next;
1789 + ebpf_pid_data_t *local_pid = ebpf_get_pid_data(pid, 0, NULL, EBPF_MODULE_SOCKET_IDX);
1790 + ebpf_socket_publish_apps_t *ws = local_pid->socket;
1791 + if (!ws)
1792 + continue;
1793 +
1794 + values->call_tcp_v4_connection = ws->call_tcp_v4_connection;
1795 + values->call_tcp_v6_connection = ws->call_tcp_v6_connection;
1796 + values->bytes_sent = ws->bytes_sent;
1797 + values->bytes_received = ws->bytes_received;
1798 + values->call_tcp_sent = ws->call_tcp_sent;
1799 + values->call_tcp_received = ws->call_tcp_received;
1800 + values->retransmit = ws->retransmit;
1801 + values->call_udp_sent = ws->call_udp_sent;
1802 + values->call_udp_received = ws->call_udp_received;
1803 }
1804 }
1805 }
@@ -1806,6 +1824,9 @@ void *ebpf_read_socket_thread(void *ptr)
1824
1825 int update_every = em->update_every;
1826 int counter = update_every - 1;
1827 + int collect_pid = (em->apps_charts || em->cgroup_charts);
1828 + if (!collect_pid)
1829 + return NULL;
1830
1831 uint32_t running_time = 0;
1832 uint32_t lifetime = em->lifetime;
@@ -1969,14 +1990,8 @@ static void ebpf_socket_read_hash_global_tables(netdata_idx_t *stats, int maps_p
1990 * @param current_pid the PID that I am updating
1991 * @param ns the structure with data read from memory.
1992 */
1972 -void ebpf_socket_fill_publish_apps(uint32_t current_pid, netdata_socket_t *ns)
1993 +void ebpf_socket_fill_publish_apps(ebpf_socket_publish_apps_t *curr, netdata_socket_t *ns)
1994 {
1974 - ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(current_pid, 0);
1975 - if (!local_pid)
1976 - return;
1977 -
1978 - ebpf_socket_publish_apps_t *curr = &local_pid->socket;
1979 -
1995 curr->bytes_sent = ns->tcp.tcp_bytes_sent;
1996 curr->bytes_received = ns->tcp.tcp_bytes_received;
1997 curr->call_tcp_sent = ns->tcp.call_tcp_sent;
@@ -2005,21 +2020,21 @@ static void ebpf_update_socket_cgroup()
2020 for (pids = ect->pids; pids; pids = pids->next) {
2021 int pid = pids->pid;
2022 ebpf_socket_publish_apps_t *publish = &ect->publish_socket;
2008 - ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(pid, 0);
2009 - if (local_pid) {
2010 - ebpf_socket_publish_apps_t *in = &local_pid->socket;
2011 -
2012 - publish->bytes_sent = in->bytes_sent;
2013 - publish->bytes_received = in->bytes_received;
2014 - publish->call_tcp_sent = in->call_tcp_sent;
2015 - publish->call_tcp_received = in->call_tcp_received;
2016 - publish->retransmit = in->retransmit;
2017 - publish->call_udp_sent = in->call_udp_sent;
2018 - publish->call_udp_received = in->call_udp_received;
2019 - publish->call_close = in->call_close;
2020 - publish->call_tcp_v4_connection = in->call_tcp_v4_connection;
2021 - publish->call_tcp_v6_connection = in->call_tcp_v6_connection;
2022 - }
2023 + ebpf_pid_data_t *local_pid = ebpf_get_pid_data(pid, 0, NULL, EBPF_MODULE_SOCKET_IDX);
2024 + ebpf_socket_publish_apps_t *in = local_pid->socket;
2025 + if (!in)
2026 + continue;
2027 +
2028 + publish->bytes_sent = in->bytes_sent;
2029 + publish->bytes_received = in->bytes_received;
2030 + publish->call_tcp_sent = in->call_tcp_sent;
2031 + publish->call_tcp_received = in->call_tcp_received;
2032 + publish->retransmit = in->retransmit;
2033 + publish->call_udp_sent = in->call_udp_sent;
2034 + publish->call_udp_received = in->call_udp_received;
2035 + publish->call_close = in->call_close;
2036 + publish->call_tcp_v4_connection = in->call_tcp_v4_connection;
2037 + publish->call_tcp_v6_connection = in->call_tcp_v6_connection;
2038 }
2039 }
2040 pthread_mutex_unlock(&mutex_cgroup_shm);
src/collectors/ebpf.plugin/ebpf_socket.h
+2 -3
@@ -157,7 +157,7 @@ typedef enum ebpf_socket_idx {
157 #define NETDATA_EBPF_PID_SOCKET_ARAL_TABLE_NAME "ebpf_pid_socket"
158 #define NETDATA_EBPF_SOCKET_ARAL_TABLE_NAME "ebpf_socket_tbl"
159
160 -typedef struct ebpf_socket_publish_apps {
160 +typedef struct __attribute__((packed)) ebpf_socket_publish_apps {
161 // Data read
162 uint64_t bytes_sent; // Bytes sent
163 uint64_t bytes_received; // Bytes received
@@ -342,8 +342,7 @@ void ebpf_parse_service_name_section(struct config *cfg);
342 void ebpf_parse_ips_unsafe(char *ptr);
343 void ebpf_parse_ports(char *ptr);
344 void ebpf_socket_read_open_connections(BUFFER *buf, struct ebpf_module *em);
345 -void ebpf_socket_fill_publish_apps(uint32_t current_pid, netdata_socket_t *ns);
346 -
345 +void ebpf_socket_fill_publish_apps(ebpf_socket_publish_apps_t *curr, netdata_socket_t *ns);
346
347 extern struct config socket_config;
348 extern netdata_ebpf_targets_t socket_targets[];
src/collectors/ebpf.plugin/ebpf_swap.c
+45 -31
@@ -10,7 +10,7 @@ static netdata_publish_syscall_t swap_publish_aggregated[NETDATA_SWAP_END];
10 static netdata_idx_t swap_hash_values[NETDATA_SWAP_END];
11 static netdata_idx_t *swap_values = NULL;
12
13 -netdata_publish_swap_t *swap_vector = NULL;
13 +netdata_ebpf_swap_t *swap_vector = NULL;
14
15 struct config swap_config = { .first_section = NULL,
16 .last_section = NULL,
@@ -393,6 +393,10 @@ static void ebpf_swap_exit(void *ptr)
393 {
394 ebpf_module_t *em = (ebpf_module_t *)ptr;
395
396 + pthread_mutex_lock(&lock);
397 + collect_pids &= ~(1<<EBPF_MODULE_SWAP_IDX);
398 + pthread_mutex_unlock(&lock);
399 +
400 if (ebpf_read_swap.thread)
401 nd_thread_signal_cancel(ebpf_read_swap.thread);
402
@@ -447,14 +451,21 @@ static void ebpf_swap_exit(void *ptr)
451 * @param out the vector with read values.
452 * @param maps_per_core do I need to read all cores?
453 */
450 -static void swap_apps_accumulator(netdata_publish_swap_t *out, int maps_per_core)
454 +static void swap_apps_accumulator(netdata_ebpf_swap_t *out, int maps_per_core)
455 {
456 int i, end = (maps_per_core) ? ebpf_nprocs : 1;
453 - netdata_publish_swap_t *total = &out[0];
457 + netdata_ebpf_swap_t *total = &out[0];
458 + uint64_t ct = total->ct;
459 for (i = 1; i < end; i++) {
455 - netdata_publish_swap_t *w = &out[i];
460 + netdata_ebpf_swap_t *w = &out[i];
461 total->write += w->write;
462 total->read += w->read;
463 +
464 + if (w->ct > ct)
465 + ct = w->ct;
466 +
467 + if (!total->name[0] && w->name[0])
468 + strncpyz(total->name, w->name, sizeof(total->name) - 1);
469 }
470 }
471
@@ -472,12 +483,11 @@ static void ebpf_update_swap_cgroup()
483 for (pids = ect->pids; pids; pids = pids->next) {
484 int pid = pids->pid;
485 netdata_publish_swap_t *out = &pids->swap;
475 - ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(pid, 0);
476 - if (local_pid) {
477 - netdata_publish_swap_t *in = &local_pid->swap;
478 -
479 - memcpy(out, in, sizeof(netdata_publish_swap_t));
480 - }
486 + ebpf_pid_data_t *local_pid = ebpf_get_pid_data(pid, 0, NULL, EBPF_MODULE_SWAP_IDX);
487 + netdata_publish_swap_t *in = local_pid->swap;
488 + if (!in)
489 + continue;
490 + memcpy(out, in, sizeof(netdata_publish_swap_t));
491 }
492 }
493 pthread_mutex_unlock(&mutex_cgroup_shm);
@@ -496,15 +506,15 @@ static void ebpf_swap_sum_pids(netdata_publish_swap_t *swap, struct ebpf_pid_on_
506 uint64_t local_read = 0;
507 uint64_t local_write = 0;
508
499 - while (root) {
509 + for (; root; root = root->next) {
510 int32_t pid = root->pid;
501 - ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(pid, 0);
502 - if (local_pid) {
503 - netdata_publish_swap_t *w = &local_pid->swap;
504 - local_write += w->write;
505 - local_read += w->read;
506 - }
507 - root = root->next;
511 + ebpf_pid_data_t *local_pid = ebpf_get_pid_data(pid, 0, NULL, EBPF_MODULE_SWAP_IDX);
512 + netdata_publish_swap_t *w = local_pid->swap;
513 + if (!w)
514 + continue;
515 +
516 + local_write += w->write;
517 + local_read += w->read;
518 }
519
520 // These conditions were added, because we are using incremental algorithm
@@ -532,12 +542,13 @@ void ebpf_swap_resume_apps_data() {
542 * Read the apps table and store data inside the structure.
543 *
544 * @param maps_per_core do I need to read all cores?
545 + * @param max_period limit of iterations without updates before remove data from hash table
546 */
536 -static void ebpf_read_swap_apps_table(int maps_per_core, int max_period)
547 +static void ebpf_read_swap_apps_table(int maps_per_core, uint32_t max_period)
548 {
538 - netdata_publish_swap_t *cv = swap_vector;
549 + netdata_ebpf_swap_t *cv = swap_vector;
550 int fd = swap_maps[NETDATA_PID_SWAP_TABLE].map_fd;
540 - size_t length = sizeof(netdata_publish_swap_t);
551 + size_t length = sizeof(netdata_ebpf_swap_t);
552 if (maps_per_core)
553 length *= ebpf_nprocs;
554
@@ -549,17 +560,17 @@ static void ebpf_read_swap_apps_table(int maps_per_core, int max_period)
560
561 swap_apps_accumulator(cv, maps_per_core);
562
552 - ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(key, cv->tgid);
553 - if (!local_pid)
554 - goto end_swap_loop;
555 -
556 - netdata_publish_swap_t *publish = &local_pid->swap;
563 + ebpf_pid_data_t *local_pid = ebpf_get_pid_data(key, cv->tgid, cv->name, EBPF_MODULE_SWAP_IDX);
564 + netdata_publish_swap_t *publish = local_pid->swap;
565 + if (!publish)
566 + local_pid->swap = publish = ebpf_swap_allocate_publish_swap();
567 if (!publish->ct || publish->ct != cv->ct) {
568 memcpy(publish, cv, sizeof(netdata_publish_swap_t));
569 local_pid->not_updated = 0;
560 - } else if (++local_pid->not_updated >= max_period) {
561 - bpf_map_delete_elem(fd, &key);
562 - local_pid->not_updated = 0;
570 + } else if (++local_pid->not_updated >= max_period && !local_pid->has_proc_file) {
571 + ebpf_release_pid_data(local_pid, fd, key, EBPF_MODULE_SWAP_IDX);
572 + ebpf_release_publish_swap(publish);
573 + local_pid->swap = NULL;
574 }
575
576 // We are cleaning to avoid passing data read from one process to other.
@@ -587,13 +598,16 @@ void *ebpf_read_swap_thread(void *ptr)
598
599 int maps_per_core = em->maps_per_core;
600 int update_every = em->update_every;
601 + int collect_pid = (em->apps_charts || em->cgroup_charts);
602 + if (!collect_pid)
603 + return NULL;
604
605 int counter = update_every - 1;
606
607 uint32_t lifetime = em->lifetime;
608 uint32_t running_time = 0;
609 usec_t period = update_every * USEC_PER_SEC;
596 - int max_period = update_every * EBPF_CLEANUP_FACTOR;
610 + uint32_t max_period = EBPF_CLEANUP_FACTOR;
611
612 while (!ebpf_plugin_stop() && running_time < lifetime) {
613 (void)heartbeat_next(&hb, period);
@@ -1017,7 +1031,7 @@ void ebpf_swap_create_apps_charts(struct ebpf_module *em, void *ptr)
1031 */
1032 static void ebpf_swap_allocate_global_vectors()
1033 {
1020 - swap_vector = callocz((size_t)ebpf_nprocs, sizeof(netdata_publish_swap_t));
1034 + swap_vector = callocz((size_t)ebpf_nprocs, sizeof(netdata_ebpf_swap_t));
1035
1036 swap_values = callocz((size_t)ebpf_nprocs, sizeof(netdata_idx_t));
1037
src/collectors/ebpf.plugin/ebpf_swap.h
+11 -4
@@ -24,16 +24,23 @@
24 #define NETDATA_SYSTEMD_SWAP_READ_CONTEXT "systemd.service.swap_read"
25 #define NETDATA_SYSTEMD_SWAP_WRITE_CONTEXT "systemd.service.swap_write"
26
27 -typedef struct netdata_publish_swap {
27 +typedef struct __attribute__((packed)) netdata_publish_swap {
28 + uint64_t ct;
29 +
30 + uint32_t read;
31 + uint32_t write;
32 +} netdata_publish_swap_t;
33 +
34 +typedef struct netdata_ebpf_swap {
35 uint64_t ct;
36 uint32_t tgid;
37 uint32_t uid;
38 uint32_t gid;
39 char name[TASK_COMM_LEN];
40
34 - uint64_t read;
35 - uint64_t write;
36 -} netdata_publish_swap_t;
41 + uint32_t read;
42 + uint32_t write;
43 +} netdata_ebpf_swap_t;
44
45 enum swap_tables {
46 NETDATA_PID_SWAP_TABLE,
src/collectors/ebpf.plugin/ebpf_vfs.c
+117 -78
@@ -11,7 +11,7 @@ static char *vfs_id_names[NETDATA_KEY_PUBLISH_VFS_END] = { "vfs_unlink", "vfs_re
11 static netdata_idx_t *vfs_hash_values = NULL;
12 static netdata_syscall_stat_t vfs_aggregated_data[NETDATA_KEY_PUBLISH_VFS_END];
13 static netdata_publish_syscall_t vfs_publish_aggregated[NETDATA_KEY_PUBLISH_VFS_END];
14 -netdata_publish_vfs_t *vfs_vector = NULL;
14 +netdata_ebpf_vfs_t *vfs_vector = NULL;
15
16 static ebpf_local_maps_t vfs_maps[] = {{.name = "tbl_vfs_pid", .internal_input = ND_EBPF_DEFAULT_PID_SIZE,
17 .user_input = 0, .type = NETDATA_EBPF_MAP_RESIZABLE | NETDATA_EBPF_MAP_PID,
@@ -881,6 +881,10 @@ static void ebpf_vfs_exit(void *pptr)
881 ebpf_module_t *em = CLEANUP_FUNCTION_GET_PTR(pptr);
882 if(!em) return;
883
884 + pthread_mutex_lock(&lock);
885 + collect_pids &= ~(1<<EBPF_MODULE_VFS_IDX);
886 + pthread_mutex_unlock(&lock);
887 +
888 if (ebpf_read_vfs.thread)
889 nd_thread_signal_cancel(ebpf_read_vfs.thread);
890
@@ -1028,6 +1032,74 @@ static void ebpf_vfs_read_global_table(netdata_idx_t *stats, int maps_per_core)
1032 (uint64_t)res[NETDATA_KEY_BYTES_VFS_READV];
1033 }
1034
1035 +/**
1036 + * Set VFS
1037 + *
1038 + * Set vfs structure with values from ebpf structure.
1039 + *
1040 + * @param vfs the output structure.
1041 + * @param w the input data.
1042 + */
1043 +static inline void vfs_aggregate_set_vfs(netdata_publish_vfs_t *vfs, netdata_ebpf_vfs_t *w)
1044 +{
1045 + vfs->write_call = w->write_call;
1046 + vfs->writev_call = w->writev_call;
1047 + vfs->read_call = w->read_call;
1048 + vfs->readv_call = w->readv_call;
1049 + vfs->unlink_call = w->unlink_call;
1050 + vfs->fsync_call = w->fsync_call;
1051 + vfs->open_call = w->open_call;
1052 + vfs->create_call = w->create_call;
1053 +
1054 + vfs->write_bytes = w->write_bytes;
1055 + vfs->writev_bytes = w->writev_bytes;
1056 + vfs->read_bytes = w->read_bytes;
1057 + vfs->readv_bytes = w->readv_bytes;
1058 +
1059 + vfs->write_err = w->write_err;
1060 + vfs->writev_err = w->writev_err;
1061 + vfs->read_err = w->read_err;
1062 + vfs->readv_err = w->readv_err;
1063 + vfs->unlink_err = w->unlink_err;
1064 + vfs->fsync_err = w->fsync_err;
1065 + vfs->open_err = w->open_err;
1066 + vfs->create_err = w->create_err;
1067 +}
1068 +
1069 +/**
1070 + * Aggregate Publish VFS
1071 + *
1072 + * Aggregate data from w source.
1073 + *
1074 + * @param vfs the output structure.
1075 + * @param w the input data.
1076 + */
1077 +static inline void vfs_aggregate_publish_vfs(netdata_publish_vfs_t *vfs, netdata_publish_vfs_t *w)
1078 +{
1079 + vfs->write_call += w->write_call;
1080 + vfs->writev_call += w->writev_call;
1081 + vfs->read_call += w->read_call;
1082 + vfs->readv_call += w->readv_call;
1083 + vfs->unlink_call += w->unlink_call;
1084 + vfs->fsync_call += w->fsync_call;
1085 + vfs->open_call += w->open_call;
1086 + vfs->create_call += w->create_call;
1087 +
1088 + vfs->write_bytes += w->write_bytes;
1089 + vfs->writev_bytes += w->writev_bytes;
1090 + vfs->read_bytes += w->read_bytes;
1091 + vfs->readv_bytes += w->readv_bytes;
1092 +
1093 + vfs->write_err += w->write_err;
1094 + vfs->writev_err += w->writev_err;
1095 + vfs->read_err += w->read_err;
1096 + vfs->readv_err += w->readv_err;
1097 + vfs->unlink_err += w->unlink_err;
1098 + vfs->fsync_err += w->fsync_err;
1099 + vfs->open_err += w->open_err;
1100 + vfs->create_err += w->create_err;
1101 +}
1102 +
1103 /**
1104 * Sum PIDs
1105 *
@@ -1038,63 +1110,17 @@ static void ebpf_vfs_read_global_table(netdata_idx_t *stats, int maps_per_core)
1110 */
1111 static void ebpf_vfs_sum_pids(netdata_publish_vfs_t *vfs, struct ebpf_pid_on_target *root)
1112 {
1041 - netdata_publish_vfs_t accumulator;
1042 - memset(&accumulator, 0, sizeof(accumulator));
1113 + memset(vfs, 0, sizeof(netdata_publish_vfs_t));
1114
1044 - while (root) {
1115 + for (; root; root = root->next) {
1116 int32_t pid = root->pid;
1046 - ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(pid, 0);
1047 - if (local_pid) {
1048 - netdata_publish_vfs_t *w = &local_pid->vfs;
1049 - accumulator.write_call += w->write_call;
1050 - accumulator.writev_call += w->writev_call;
1051 - accumulator.read_call += w->read_call;
1052 - accumulator.readv_call += w->readv_call;
1053 - accumulator.unlink_call += w->unlink_call;
1054 - accumulator.fsync_call += w->fsync_call;
1055 - accumulator.open_call += w->open_call;
1056 - accumulator.create_call += w->create_call;
1057 -
1058 - accumulator.write_bytes += w->write_bytes;
1059 - accumulator.writev_bytes += w->writev_bytes;
1060 - accumulator.read_bytes += w->read_bytes;
1061 - accumulator.readv_bytes += w->readv_bytes;
1062 -
1063 - accumulator.write_err += w->write_err;
1064 - accumulator.writev_err += w->writev_err;
1065 - accumulator.read_err += w->read_err;
1066 - accumulator.readv_err += w->readv_err;
1067 - accumulator.unlink_err += w->unlink_err;
1068 - accumulator.fsync_err += w->fsync_err;
1069 - accumulator.open_err += w->open_err;
1070 - accumulator.create_err += w->create_err;
1071 - }
1072 - root = root->next;
1073 - }
1074 -
1075 - // These conditions were added, because we are using incremental algorithm
1076 - vfs->write_call = (accumulator.write_call >= vfs->write_call) ? accumulator.write_call : vfs->write_call;
1077 - vfs->writev_call = (accumulator.writev_call >= vfs->writev_call) ? accumulator.writev_call : vfs->writev_call;
1078 - vfs->read_call = (accumulator.read_call >= vfs->read_call) ? accumulator.read_call : vfs->read_call;
1079 - vfs->readv_call = (accumulator.readv_call >= vfs->readv_call) ? accumulator.readv_call : vfs->readv_call;
1080 - vfs->unlink_call = (accumulator.unlink_call >= vfs->unlink_call) ? accumulator.unlink_call : vfs->unlink_call;
1081 - vfs->fsync_call = (accumulator.fsync_call >= vfs->fsync_call) ? accumulator.fsync_call : vfs->fsync_call;
1082 - vfs->open_call = (accumulator.open_call >= vfs->open_call) ? accumulator.open_call : vfs->open_call;
1083 - vfs->create_call = (accumulator.create_call >= vfs->create_call) ? accumulator.create_call : vfs->create_call;
1084 -
1085 - vfs->write_bytes = (accumulator.write_bytes >= vfs->write_bytes) ? accumulator.write_bytes : vfs->write_bytes;
1086 - vfs->writev_bytes = (accumulator.writev_bytes >= vfs->writev_bytes) ? accumulator.writev_bytes : vfs->writev_bytes;
1087 - vfs->read_bytes = (accumulator.read_bytes >= vfs->read_bytes) ? accumulator.read_bytes : vfs->read_bytes;
1088 - vfs->readv_bytes = (accumulator.readv_bytes >= vfs->readv_bytes) ? accumulator.readv_bytes : vfs->readv_bytes;
1117 + ebpf_pid_data_t *local_pid = ebpf_get_pid_data(pid, 0, NULL, EBPF_MODULE_VFS_IDX);
1118 + netdata_publish_vfs_t *w = local_pid->vfs;
1119 + if (!w)
1120 + continue;
1121
1090 - vfs->write_err = (accumulator.write_err >= vfs->write_err) ? accumulator.write_err : vfs->write_err;
1091 - vfs->writev_err = (accumulator.writev_err >= vfs->writev_err) ? accumulator.writev_err : vfs->writev_err;
1092 - vfs->read_err = (accumulator.read_err >= vfs->read_err) ? accumulator.read_err : vfs->read_err;
1093 - vfs->readv_err = (accumulator.readv_err >= vfs->readv_err) ? accumulator.readv_err : vfs->readv_err;
1094 - vfs->unlink_err = (accumulator.unlink_err >= vfs->unlink_err) ? accumulator.unlink_err : vfs->unlink_err;
1095 - vfs->fsync_err = (accumulator.fsync_err >= vfs->fsync_err) ? accumulator.fsync_err : vfs->fsync_err;
1096 - vfs->open_err = (accumulator.open_err >= vfs->open_err) ? accumulator.open_err : vfs->open_err;
1097 - vfs->create_err = (accumulator.create_err >= vfs->create_err) ? accumulator.create_err : vfs->create_err;
1122 + vfs_aggregate_publish_vfs(vfs, w);
1123 + }
1124 }
1125
1126 /**
@@ -1183,12 +1209,13 @@ void ebpf_vfs_send_apps_data(ebpf_module_t *em, struct ebpf_target *root)
1209 *
1210 * @param out the vector with read values.
1211 */
1186 -static void vfs_apps_accumulator(netdata_publish_vfs_t *out, int maps_per_core)
1212 +static void vfs_apps_accumulator(netdata_ebpf_vfs_t *out, int maps_per_core)
1213 {
1214 int i, end = (maps_per_core) ? ebpf_nprocs : 1;
1189 - netdata_publish_vfs_t *total = &out[0];
1215 + netdata_ebpf_vfs_t *total = &out[0];
1216 + uint64_t ct = total->ct;
1217 for (i = 1; i < end; i++) {
1191 - netdata_publish_vfs_t *w = &out[i];
1218 + netdata_ebpf_vfs_t *w = &out[i];
1219
1220 total->write_call += w->write_call;
1221 total->writev_call += w->writev_call;
@@ -1206,17 +1233,23 @@ static void vfs_apps_accumulator(netdata_publish_vfs_t *out, int maps_per_core)
1233 total->read_err += w->read_err;
1234 total->readv_err += w->readv_err;
1235 total->unlink_err += w->unlink_err;
1236 +
1237 + if (w->ct > ct)
1238 + ct = w->ct;
1239 +
1240 + if (!total->name[0] && w->name[0])
1241 + strncpyz(total->name, w->name, sizeof(total->name) - 1);
1242 }
1243 }
1244
1245 /**
1246 * Read the hash table and store data to allocated vectors.
1247 */
1215 -static void ebpf_vfs_read_apps(int maps_per_core, int max_period)
1248 +static void ebpf_vfs_read_apps(int maps_per_core, uint32_t max_period)
1249 {
1217 - netdata_publish_vfs_t *vv = vfs_vector;
1250 + netdata_ebpf_vfs_t *vv = vfs_vector;
1251 int fd = vfs_maps[NETDATA_VFS_PID].map_fd;
1219 - size_t length = sizeof(netdata_publish_vfs_t);
1252 + size_t length = sizeof(netdata_ebpf_vfs_t);
1253 if (maps_per_core)
1254 length *= ebpf_nprocs;
1255
@@ -1228,17 +1261,17 @@ static void ebpf_vfs_read_apps(int maps_per_core, int max_period)
1261
1262 vfs_apps_accumulator(vv, maps_per_core);
1263
1231 - ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(key, vv->tgid);
1232 - if (!local_pid)
1233 - goto end_vfs_loop;
1234 -
1235 - netdata_publish_vfs_t *publish = &local_pid->vfs;
1264 + ebpf_pid_data_t *local_pid = ebpf_get_pid_data(key, vv->tgid, vv->name, EBPF_MODULE_VFS_IDX);
1265 + netdata_publish_vfs_t *publish = local_pid->vfs;
1266 + if (!publish)
1267 + local_pid->vfs = publish = ebpf_vfs_allocate_publish();
1268 if (!publish->ct || publish->ct != vv->ct) {
1237 - memcpy(publish, vv, sizeof(netdata_publish_vfs_t));
1269 + vfs_aggregate_set_vfs(publish, vv);
1270 local_pid->not_updated = 0;
1271 } else if (++local_pid->not_updated >= max_period){
1240 - bpf_map_delete_elem(fd, &key);
1241 - local_pid->not_updated = 0;
1272 + ebpf_release_pid_data(local_pid, fd, key, EBPF_MODULE_VFS_IDX);
1273 + ebpf_vfs_release_publish(publish);
1274 + local_pid->vfs = NULL;
1275 }
1276
1277 end_vfs_loop:
@@ -1264,12 +1297,14 @@ static void read_update_vfs_cgroup()
1297 for (pids = ect->pids; pids; pids = pids->next) {
1298 int pid = pids->pid;
1299 netdata_publish_vfs_t *out = &pids->vfs;
1267 - ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(pid, 0);
1268 - if (local_pid) {
1269 - netdata_publish_vfs_t *in = &local_pid->vfs;
1300 + memset(out, 0, sizeof(netdata_publish_vfs_t));
1301
1271 - memcpy(out, in, sizeof(netdata_publish_vfs_t));
1272 - }
1302 + ebpf_pid_data_t *local_pid = ebpf_get_pid_data(pid, 0, NULL, EBPF_MODULE_VFS_IDX);
1303 + netdata_publish_vfs_t *in = local_pid->vfs;
1304 + if (!in)
1305 + continue;
1306 +
1307 + vfs_aggregate_publish_vfs(out, in);
1308 }
1309 }
1310 pthread_mutex_unlock(&mutex_cgroup_shm);
@@ -1284,7 +1319,7 @@ static void read_update_vfs_cgroup()
1319 * @param pids input data
1320 */
1321 static void ebpf_vfs_sum_cgroup_pids(netdata_publish_vfs_t *vfs, struct pid_on_target2 *pids)
1287 - {
1322 +{
1323 netdata_publish_vfs_t accumulator;
1324 memset(&accumulator, 0, sizeof(accumulator));
1325
@@ -2031,13 +2066,16 @@ void *ebpf_read_vfs_thread(void *ptr)
2066
2067 int maps_per_core = em->maps_per_core;
2068 int update_every = em->update_every;
2069 + int collect_pid = (em->apps_charts || em->cgroup_charts);
2070 + if (!collect_pid)
2071 + return NULL;
2072
2073 int counter = update_every - 1;
2074
2075 uint32_t lifetime = em->lifetime;
2076 uint32_t running_time = 0;
2077 usec_t period = update_every * USEC_PER_SEC;
2040 - int max_period = update_every * EBPF_CLEANUP_FACTOR;
2078 + uint32_t max_period = EBPF_CLEANUP_FACTOR;
2079 while (!ebpf_plugin_stop() && running_time < lifetime) {
2080 (void)heartbeat_next(&hb, period);
2081 if (ebpf_plugin_stop() || ++counter != update_every)
@@ -2527,7 +2565,7 @@ void ebpf_vfs_create_apps_charts(struct ebpf_module *em, void *ptr)
2565 */
2566 static void ebpf_vfs_allocate_global_vectors()
2567 {
2530 - vfs_vector = callocz(ebpf_nprocs, sizeof(netdata_publish_vfs_t));
2568 + vfs_vector = callocz(ebpf_nprocs, sizeof(netdata_ebpf_vfs_t));
2569
2570 memset(vfs_aggregated_data, 0, sizeof(vfs_aggregated_data));
2571 memset(vfs_publish_aggregated, 0, sizeof(vfs_publish_aggregated));
@@ -2618,7 +2656,8 @@ void *ebpf_vfs_thread(void *ptr)
2656
2657 pthread_mutex_unlock(&lock);
2658
2621 - ebpf_read_vfs.thread = nd_thread_create(ebpf_read_vfs.name, NETDATA_THREAD_OPTION_DEFAULT, ebpf_read_vfs_thread, em);
2659 + ebpf_read_vfs.thread = nd_thread_create(ebpf_read_vfs.name, NETDATA_THREAD_OPTION_DEFAULT,
2660 + ebpf_read_vfs_thread, em);
2661
2662 vfs_collector(em);
2663
src/collectors/ebpf.plugin/ebpf_vfs.h
+33 -2
@@ -75,7 +75,38 @@
75 // dimension
76 #define EBPF_COMMON_UNITS_BYTES "bytes/s"
77
78 -typedef struct netdata_publish_vfs {
78 +typedef struct __attribute__((packed)) netdata_publish_vfs {
79 + uint64_t ct;
80 +
81 + //Counter
82 + uint32_t write_call;
83 + uint32_t writev_call;
84 + uint32_t read_call;
85 + uint32_t readv_call;
86 + uint32_t unlink_call;
87 + uint32_t fsync_call;
88 + uint32_t open_call;
89 + uint32_t create_call;
90 +
91 + //Accumulator
92 + uint64_t write_bytes;
93 + uint64_t writev_bytes;
94 + uint64_t readv_bytes;
95 + uint64_t read_bytes;
96 +
97 + //Counter
98 + uint32_t write_err;
99 + uint32_t writev_err;
100 + uint32_t read_err;
101 + uint32_t readv_err;
102 + uint32_t unlink_err;
103 + uint32_t fsync_err;
104 + uint32_t open_err;
105 + uint32_t create_err;
106 +
107 +} netdata_publish_vfs_t;
108 +
109 +typedef struct netdata_ebpf_vfs {
110 uint64_t ct;
111 uint32_t tgid;
112 uint32_t uid;
@@ -107,7 +138,7 @@ typedef struct netdata_publish_vfs {
138 uint32_t fsync_err;
139 uint32_t open_err;
140 uint32_t create_err;
110 -} netdata_publish_vfs_t;
141 +} netdata_ebpf_vfs_t;
142
143 enum netdata_publish_vfs_list {
144 NETDATA_KEY_PUBLISH_VFS_UNLINK,
src/collectors/ebpf.plugin/metadata.yaml
+7
@@ -3254,6 +3254,13 @@ modules:
3254 dimensions:
3255 - name: total
3256 - name: running
3257 + - name: netdata.ebpf_pids
3258 + description: Total number of monitored PIDs
3259 + unit: "pids"
3260 + chart_type: line
3261 + dimensions:
3262 + - name: user
3263 + - name: kernel
3264 - name: netdata.ebpf_load_methods
3265 description: Load info
3266 unit: "methods"