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"