@cryptotaxi247 / netdata-1 / commits / 929b19f48

eBPF Functions (enable/disable threads) (#15214)

thiagoftsm committed Jul 12, 2023 at 16:49 UTC 929b19f485b7100d8caa322abb0987afd01b3883
69 files changed +3726 -617
.gitignore
+1
@@ -196,6 +196,7 @@ tests/acls/acl.sh
196 tests/urls/request.sh
197 tests/alarm_repetition/alarm.sh
198 tests/template_dimension/template_dim.sh
199 +tests/ebpf/ebpf_thread_function.sh
200 aclk/legacy/tests/install-fake-charts.d.sh
201
202 # tests and temp files
CMakeLists.txt
+2
@@ -624,6 +624,8 @@ set(EBPF_PROCESS_PLUGIN_FILES
624 collectors/ebpf.plugin/ebpf_cgroup.h
625 collectors/ebpf.plugin/ebpf_unittest.c
626 collectors/ebpf.plugin/ebpf_unittest.h
627 + collectors/ebpf.plugin/ebpf_functions.c
628 + collectors/ebpf.plugin/ebpf_functions.h
629 )
630
631 set(PROC_PLUGIN_FILES
Makefile.am
+2
@@ -365,6 +365,8 @@ EBPF_PLUGIN_FILES = \
365 collectors/ebpf.plugin/ebpf_cgroup.h \
366 collectors/ebpf.plugin/ebpf_unittest.c \
367 collectors/ebpf.plugin/ebpf_unittest.h \
368 + collectors/ebpf.plugin/ebpf_functions.c \
369 + collectors/ebpf.plugin/ebpf_functions.h \
370 $(LIBNETDATA_FILES) \
371 $(NULL)
372
collectors/ebpf.plugin/README.md
+54 -7
@@ -235,13 +235,12 @@ Linux metrics:
235
236 The eBPF collector enables and runs the following eBPF programs by default:
237
238 +- `cachestat`: Netdata's eBPF data collector creates charts about the memory page cache. When the integration with
239 + [`apps.plugin`](https://github.com/netdata/netdata/blob/master/collectors/apps.plugin/README.md) is enabled, this collector creates charts for the whole host _and_
240 + for each application.
241 - `fd` : This eBPF program creates charts that show information about calls to open files.
242 - `mount`: This eBPF program creates charts that show calls to syscalls mount(2) and umount(2).
243 - `shm`: This eBPF program creates charts that show calls to syscalls shmget(2), shmat(2), shmdt(2) and shmctl(2).
241 -- `sync`: Monitor calls to syscalls sync(2), fsync(2), fdatasync(2), syncfs(2), msync(2), and sync_file_range(2).
242 -- `network viewer`: This eBPF program creates charts with information about `TCP` and `UDP` functions, including the
243 - bandwidth consumed by each.
244 -- `vfs`: This eBPF program creates charts that show information about VFS (Virtual File System) functions.
244 - `process`: This eBPF program creates charts that show information about process life. When in `return` mode, it also
245 creates charts showing errors when these operations are executed.
246 - `hardirq`: This eBPF program creates charts that show information about time spent servicing individual hardware
@@ -254,9 +253,6 @@ The eBPF collector enables and runs the following eBPF programs by default:
253
254 You can also enable the following eBPF programs:
255
257 -- `cachestat`: Netdata's eBPF data collector creates charts about the memory page cache. When the integration with
258 - [`apps.plugin`](https://github.com/netdata/netdata/blob/master/collectors/apps.plugin/README.md) is enabled, this collector creates charts for the whole host _and_
259 - for each application.
256 - `dcstat` : This eBPF program creates charts that show information about file access using directory cache. It appends
257 `kprobes` for `lookup_fast()` and `d_lookup()` to identify if files are inside directory cache, outside and files are
258 not found.
@@ -264,7 +260,11 @@ You can also enable the following eBPF programs:
260 - `filesystem` : This eBPF program creates charts that show information about some filesystem latency.
261 - `swap` : This eBPF program creates charts that show information about swap access.
262 - `mdflush`: This eBPF program creates charts that show information about
263 +- `sync`: Monitor calls to syscalls sync(2), fsync(2), fdatasync(2), syncfs(2), msync(2), and sync_file_range(2).
264 +- `network viewer`: This eBPF program creates charts with information about `TCP` and `UDP` functions, including the
265 + bandwidth consumed by each.
266 multi-device software flushes.
267 +- `vfs`: This eBPF program creates charts that show information about VFS (Virtual File System) functions.
268
269 ### Configuring eBPF threads
270
@@ -989,3 +989,50 @@ shows how the lockdown module impacts `ebpf.plugin` based on the selected option
989
990 If you or your distribution compiled the kernel with the last combination, your system cannot load shared libraries
991 required to run `ebpf.plugin`.
992 +
993 +## Function
994 +
995 +The eBPF plugin has a [function](https://github.com/netdata/netdata/blob/master/docs/cloud/netdata-functions.md) named
996 +`ebpf_thread` that controls its internal threads and helps to reduce the overhead on host. Using the function you
997 +can run the plugin with all threads disabled and enable them only when you want to take a look in specific areas.
998 +
999 +### List threads
1000 +
1001 +To list all threads status you can query directly the endpoint function:
1002 +
1003 +`http://localhost:19999/api/v1/function?function=ebpf_thread`
1004 +
1005 +It is also possible to query a specific thread adding keyword `thread` and thread name:
1006 +
1007 +`http://localhost:19999/api/v1/function?function=ebpf_thread%20thread:mount`
1008 +
1009 +### Enable thread
1010 +
1011 +It is possible to enable a specific thread using the keyword `enable`:
1012 +
1013 +`http://localhost:19999/api/v1/function?function=ebpf_thread%20enable:mount`
1014 +
1015 +this will run thread `mount` during 300 seconds (5 minutes). You can specify a specific period by appending the period
1016 +after the thread name:
1017 +
1018 +`http://localhost:19999/api/v1/function?function=ebpf_thread%20enable:mount:600`
1019 +
1020 +in this example thread `mount` will run during 600 seconds (10 minutes).
1021 +
1022 +### Disable thread
1023 +
1024 +It is also possible to stop any thread running using the keyword `disable`. For example, to disable `cachestat` you can
1025 +request:
1026 +
1027 +`http://localhost:19999/api/v1/function?function=ebpf_thread%20disable:cachestat`
1028 +
1029 +### Debugging threads
1030 +
1031 +You can verify the impact of threads on the host by running the
1032 +[ebpf_thread_function.sh](https://github.com/netdata/netdata/blob/master/tests/ebpf/ebpf_thread_function.sh)
1033 +script on your environment.
1034 +
1035 +You can check the results of having threads running on your environment in the Netdata monitoring section on your
1036 +dashboard
1037 +
1038 +<img src="https://github.com/netdata/netdata/assets/49162938/91823573-114c-4c16-b634-cc46f7bb1bcf" alt="Threads running." />
collectors/ebpf.plugin/ebpf.c
+500 -187
@@ -30,6 +30,8 @@ int ebpf_nprocs;
30 int isrh = 0;
31 int main_thread_id = 0;
32 int process_pid_fd = -1;
33 +static size_t global_iterations_counter = 1;
34 +bool publish_internal_metrics = true;
35
36 pthread_mutex_t lock;
37 pthread_mutex_t ebpf_exit_cleanup;
@@ -47,7 +49,8 @@ struct netdata_static_thread cgroup_integration_thread = {
49 };
50
51 ebpf_module_t ebpf_modules[] = {
50 - { .thread_name = "process", .config_name = "process", .enabled = 0, .start_routine = ebpf_process_thread,
52 + { .thread_name = "process", .config_name = "process", .thread_description = NETDATA_EBPF_MODULE_PROCESS_DESC,
53 + .enabled = 0, .start_routine = ebpf_process_thread,
54 .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
55 .apps_level = NETDATA_APPS_LEVEL_REAL_PARENT, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
56 .apps_routine = ebpf_process_create_apps_charts, .maps = NULL,
@@ -56,8 +59,9 @@ ebpf_module_t ebpf_modules[] = {
59 .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_10 |
60 NETDATA_V5_14,
61 .load = EBPF_LOAD_LEGACY, .targets = NULL, .probe_links = NULL, .objects = NULL,
59 - .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES},
60 - { .thread_name = "socket", .config_name = "socket", .enabled = 0, .start_routine = ebpf_socket_thread,
62 + .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0 },
63 + { .thread_name = "socket", .config_name = "socket", .thread_description = NETDATA_EBPF_SOCKET_MODULE_DESC,
64 + .enabled = 0, .start_routine = ebpf_socket_thread,
65 .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
66 .apps_level = NETDATA_APPS_LEVEL_REAL_PARENT, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
67 .apps_routine = ebpf_socket_create_apps_charts, .maps = NULL,
@@ -65,8 +69,9 @@ ebpf_module_t ebpf_modules[] = {
69 .config_file = NETDATA_NETWORK_CONFIG_FILE,
70 .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
71 .load = EBPF_LOAD_LEGACY, .targets = socket_targets, .probe_links = NULL, .objects = NULL,
68 - .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES},
69 - { .thread_name = "cachestat", .config_name = "cachestat", .enabled = 0, .start_routine = ebpf_cachestat_thread,
72 + .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
73 + { .thread_name = "cachestat", .config_name = "cachestat", .thread_description = NETDATA_EBPF_CACHESTAT_MODULE_DESC,
74 + .enabled = 0, .start_routine = ebpf_cachestat_thread,
75 .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
76 .apps_level = NETDATA_APPS_LEVEL_REAL_PARENT, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
77 .apps_routine = ebpf_cachestat_create_apps_charts, .maps = cachestat_maps,
@@ -75,8 +80,9 @@ ebpf_module_t ebpf_modules[] = {
80 .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18|
81 NETDATA_V5_4 | NETDATA_V5_14 | NETDATA_V5_15 | NETDATA_V5_16,
82 .load = EBPF_LOAD_LEGACY, .targets = cachestat_targets, .probe_links = NULL, .objects = NULL,
78 - .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES},
79 - { .thread_name = "sync", .config_name = "sync", .enabled = 0, .start_routine = ebpf_sync_thread,
83 + .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
84 + { .thread_name = "sync", .config_name = "sync", .thread_description = NETDATA_EBPF_SYNC_MODULE_DESC,
85 + .enabled = 0, .start_routine = ebpf_sync_thread,
86 .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
87 .apps_level = NETDATA_APPS_NOT_SET, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
88 .apps_routine = NULL, .maps = NULL, .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &sync_config,
@@ -84,8 +90,9 @@ ebpf_module_t ebpf_modules[] = {
90 // All syscalls have the same kernels
91 .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
92 .load = EBPF_LOAD_LEGACY, .targets = sync_targets, .probe_links = NULL, .objects = NULL,
87 - .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES},
88 - { .thread_name = "dc", .config_name = "dc", .enabled = 0, .start_routine = ebpf_dcstat_thread,
93 + .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
94 + { .thread_name = "dc", .config_name = "dc", .thread_description = NETDATA_EBPF_DC_MODULE_DESC,
95 + .enabled = 0, .start_routine = ebpf_dcstat_thread,
96 .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
97 .apps_level = NETDATA_APPS_LEVEL_REAL_PARENT, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
98 .apps_routine = ebpf_dcstat_create_apps_charts, .maps = dcstat_maps,
@@ -93,8 +100,9 @@ ebpf_module_t ebpf_modules[] = {
100 .config_file = NETDATA_DIRECTORY_DCSTAT_CONFIG_FILE,
101 .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
102 .load = EBPF_LOAD_LEGACY, .targets = dc_targets, .probe_links = NULL, .objects = NULL,
96 - .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES},
97 - { .thread_name = "swap", .config_name = "swap", .enabled = 0, .start_routine = ebpf_swap_thread,
103 + .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
104 + { .thread_name = "swap", .config_name = "swap", .thread_description = NETDATA_EBPF_SWAP_MODULE_DESC,
105 + .enabled = 0, .start_routine = ebpf_swap_thread,
106 .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
107 .apps_level = NETDATA_APPS_LEVEL_REAL_PARENT, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
108 .apps_routine = ebpf_swap_create_apps_charts, .maps = NULL,
@@ -102,8 +110,9 @@ ebpf_module_t ebpf_modules[] = {
110 .config_file = NETDATA_DIRECTORY_SWAP_CONFIG_FILE,
111 .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
112 .load = EBPF_LOAD_LEGACY, .targets = swap_targets, .probe_links = NULL, .objects = NULL,
105 - .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES},
106 - { .thread_name = "vfs", .config_name = "vfs", .enabled = 0, .start_routine = ebpf_vfs_thread,
113 + .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
114 + { .thread_name = "vfs", .config_name = "vfs", .thread_description = NETDATA_EBPF_VFS_MODULE_DESC,
115 + .enabled = 0, .start_routine = ebpf_vfs_thread,
116 .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
117 .apps_level = NETDATA_APPS_LEVEL_REAL_PARENT, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
118 .apps_routine = ebpf_vfs_create_apps_charts, .maps = NULL,
@@ -111,32 +120,36 @@ ebpf_module_t ebpf_modules[] = {
120 .config_file = NETDATA_DIRECTORY_VFS_CONFIG_FILE,
121 .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
122 .load = EBPF_LOAD_LEGACY, .targets = vfs_targets, .probe_links = NULL, .objects = NULL,
114 - .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES},
115 - { .thread_name = "filesystem", .config_name = "filesystem", .enabled = 0, .start_routine = ebpf_filesystem_thread,
123 + .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
124 + { .thread_name = "filesystem", .config_name = "filesystem", .thread_description = NETDATA_EBPF_FS_MODULE_DESC,
125 + .enabled = 0, .start_routine = ebpf_filesystem_thread,
126 .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
127 .apps_level = NETDATA_APPS_NOT_SET, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
128 .apps_routine = NULL, .maps = NULL, .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &fs_config,
129 .config_file = NETDATA_FILESYSTEM_CONFIG_FILE,
130 //We are setting kernels as zero, because we load eBPF programs according the kernel running.
131 .kernels = 0, .load = EBPF_LOAD_LEGACY, .targets = NULL, .probe_links = NULL, .objects = NULL,
122 - .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES },
123 - { .thread_name = "disk", .config_name = "disk", .enabled = 0, .start_routine = ebpf_disk_thread,
132 + .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
133 + { .thread_name = "disk", .config_name = "disk", .thread_description = NETDATA_EBPF_DISK_MODULE_DESC,
134 + .enabled = 0, .start_routine = ebpf_disk_thread,
135 .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
136 .apps_level = NETDATA_APPS_NOT_SET, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
137 .apps_routine = NULL, .maps = NULL, .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &disk_config,
138 .config_file = NETDATA_DISK_CONFIG_FILE,
139 .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
140 .load = EBPF_LOAD_LEGACY, .targets = NULL, .probe_links = NULL, .objects = NULL,
130 - .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES},
131 - { .thread_name = "mount", .config_name = "mount", .enabled = 0, .start_routine = ebpf_mount_thread,
141 + .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
142 + { .thread_name = "mount", .config_name = "mount", .thread_description = NETDATA_EBPF_MOUNT_MODULE_DESC,
143 + .enabled = 0, .start_routine = ebpf_mount_thread,
144 .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
145 .apps_level = NETDATA_APPS_NOT_SET, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
146 .apps_routine = NULL, .maps = NULL, .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &mount_config,
147 .config_file = NETDATA_MOUNT_CONFIG_FILE,
148 .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
149 .load = EBPF_LOAD_LEGACY, .targets = mount_targets, .probe_links = NULL, .objects = NULL,
138 - .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES},
139 - { .thread_name = "fd", .config_name = "fd", .enabled = 0, .start_routine = ebpf_fd_thread,
150 + .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
151 + { .thread_name = "fd", .config_name = "fd", .thread_description = NETDATA_EBPF_FD_MODULE_DESC,
152 + .enabled = 0, .start_routine = ebpf_fd_thread,
153 .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
154 .apps_level = NETDATA_APPS_LEVEL_REAL_PARENT, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
155 .apps_routine = ebpf_fd_create_apps_charts, .maps = NULL,
@@ -145,24 +158,27 @@ ebpf_module_t ebpf_modules[] = {
158 .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_11 |
159 NETDATA_V5_14,
160 .load = EBPF_LOAD_LEGACY, .targets = fd_targets, .probe_links = NULL, .objects = NULL,
148 - .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES},
149 - { .thread_name = "hardirq", .config_name = "hardirq", .enabled = 0, .start_routine = ebpf_hardirq_thread,
161 + .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
162 + { .thread_name = "hardirq", .config_name = "hardirq", .thread_description = NETDATA_EBPF_HARDIRQ_MODULE_DESC,
163 + .enabled = 0, .start_routine = ebpf_hardirq_thread,
164 .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
165 .apps_level = NETDATA_APPS_NOT_SET, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
166 .apps_routine = NULL, .maps = NULL, .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &hardirq_config,
167 .config_file = NETDATA_HARDIRQ_CONFIG_FILE,
168 .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
169 .load = EBPF_LOAD_LEGACY, .targets = NULL, .probe_links = NULL, .objects = NULL,
156 - .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES},
157 - { .thread_name = "softirq", .config_name = "softirq", .enabled = 0, .start_routine = ebpf_softirq_thread,
170 + .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
171 + { .thread_name = "softirq", .config_name = "softirq", .thread_description = NETDATA_EBPF_SOFTIRQ_MODULE_DESC,
172 + .enabled = 0, .start_routine = ebpf_softirq_thread,
173 .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
174 .apps_level = NETDATA_APPS_NOT_SET, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
175 .apps_routine = NULL, .maps = NULL, .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &softirq_config,
176 .config_file = NETDATA_SOFTIRQ_CONFIG_FILE,
177 .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
178 .load = EBPF_LOAD_LEGACY, .targets = NULL, .probe_links = NULL, .objects = NULL,
164 - .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES},
165 - { .thread_name = "oomkill", .config_name = "oomkill", .enabled = 0, .start_routine = ebpf_oomkill_thread,
179 + .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
180 + { .thread_name = "oomkill", .config_name = "oomkill", .thread_description = NETDATA_EBPF_OOMKILL_MODULE_DESC,
181 + .enabled = 0, .start_routine = ebpf_oomkill_thread,
182 .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
183 .apps_level = NETDATA_APPS_LEVEL_REAL_PARENT, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
184 .apps_routine = ebpf_oomkill_create_apps_charts, .maps = NULL,
@@ -170,8 +186,9 @@ ebpf_module_t ebpf_modules[] = {
186 .config_file = NETDATA_OOMKILL_CONFIG_FILE,
187 .kernels = NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
188 .load = EBPF_LOAD_LEGACY, .targets = NULL, .probe_links = NULL, .objects = NULL,
173 - .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES},
174 - { .thread_name = "shm", .config_name = "shm", .enabled = 0, .start_routine = ebpf_shm_thread,
189 + .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
190 + { .thread_name = "shm", .config_name = "shm", .thread_description = NETDATA_EBPF_SHM_MODULE_DESC,
191 + .enabled = 0, .start_routine = ebpf_shm_thread,
192 .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
193 .apps_level = NETDATA_APPS_LEVEL_REAL_PARENT, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
194 .apps_routine = ebpf_shm_create_apps_charts, .maps = NULL,
@@ -179,15 +196,25 @@ ebpf_module_t ebpf_modules[] = {
196 .config_file = NETDATA_DIRECTORY_SHM_CONFIG_FILE,
197 .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
198 .load = EBPF_LOAD_LEGACY, .targets = shm_targets, .probe_links = NULL, .objects = NULL,
182 - .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES},
183 - { .thread_name = "mdflush", .config_name = "mdflush", .enabled = 0, .start_routine = ebpf_mdflush_thread,
199 + .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
200 + { .thread_name = "mdflush", .config_name = "mdflush", .thread_description = NETDATA_EBPF_MD_MODULE_DESC,
201 + .enabled = 0, .start_routine = ebpf_mdflush_thread,
202 .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
203 .apps_level = NETDATA_APPS_NOT_SET, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
204 .apps_routine = NULL, .maps = NULL, .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &mdflush_config,
205 .config_file = NETDATA_DIRECTORY_MDFLUSH_CONFIG_FILE,
206 .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
207 .load = EBPF_LOAD_LEGACY, .targets = mdflush_targets, .probe_links = NULL, .objects = NULL,
190 - .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES},
208 + .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
209 + { .thread_name = "functions", .config_name = "functions", .thread_description = NETDATA_EBPF_FUNCTIONS_MODULE_DESC,
210 + .enabled = 1, .start_routine = ebpf_function_thread,
211 + .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO,
212 + .apps_level = NETDATA_APPS_NOT_SET, .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0,
213 + .apps_routine = NULL, .maps = NULL, .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = NULL,
214 + .config_file = NETDATA_DIRECTORY_FUNCTIONS_CONFIG_FILE,
215 + .kernels = NETDATA_V3_10 | NETDATA_V4_14 | NETDATA_V4_16 | NETDATA_V4_18 | NETDATA_V5_4 | NETDATA_V5_14,
216 + .load = EBPF_LOAD_LEGACY, .targets = NULL, .probe_links = NULL, .objects = NULL,
217 + .thread = NULL, .maps_per_core = CONFIG_BOOLEAN_YES, .lifetime = EBPF_DEFAULT_LIFETIME, .running_time = 0},
218 { .thread_name = NULL, .enabled = 0, .start_routine = NULL, .update_every = EBPF_DEFAULT_UPDATE_EVERY,
219 .global_charts = 0, .apps_charts = NETDATA_EBPF_APPS_FLAG_NO, .apps_level = NETDATA_APPS_NOT_SET,
220 .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0, .apps_routine = NULL, .maps = NULL,
@@ -356,6 +383,16 @@ struct netdata_static_thread ebpf_threads[] = {
383 .init_routine = NULL,
384 .start_routine = NULL
385 },
386 + {
387 + .name = "EBPF FUNCTIONS",
388 + .config_section = NULL,
389 + .config_name = NULL,
390 + .env_name = NULL,
391 + .enabled = 1,
392 + .thread = NULL,
393 + .init_routine = NULL,
394 + .start_routine = NULL
395 + },
396 {
397 .name = NULL,
398 .config_section = NULL,
@@ -586,7 +623,7 @@ static inline void ebpf_check_before2go()
623 int j;
624 pthread_mutex_lock(&ebpf_exit_cleanup);
625 for (j = 0; ebpf_modules[j].thread_name != NULL; j++) {
589 - if (ebpf_modules[j].enabled == NETDATA_THREAD_EBPF_RUNNING)
626 + if (ebpf_modules[j].enabled < NETDATA_THREAD_EBPF_STOPPING)
627 i++;
628 }
629 pthread_mutex_unlock(&ebpf_exit_cleanup);
@@ -665,7 +702,7 @@ static void ebpf_unload_unique_maps()
702 int i;
703 for (i = 0; ebpf_modules[i].thread_name; i++) {
704 // These threads are cleaned with other functions
668 - if (i > EBPF_MODULE_SOCKET_IDX)
705 + if (i != EBPF_MODULE_SOCKET_IDX)
706 continue;
707
708 if (ebpf_modules[i].enabled != NETDATA_THREAD_EBPF_STOPPED) {
@@ -680,13 +717,10 @@ static void ebpf_unload_unique_maps()
717 continue;
718 }
719
683 - if (i == EBPF_MODULE_SOCKET_IDX) {
720 #ifdef LIBBPF_MAJOR_VERSION
685 - if (socket_bpf_obj)
686 - socket_bpf__destroy(socket_bpf_obj);
721 + if (socket_bpf_obj)
722 + socket_bpf__destroy(socket_bpf_obj);
723 #endif
688 - }
689 -
724 }
725 }
726
@@ -698,7 +732,7 @@ static void ebpf_unload_unique_maps()
732 static void ebpf_unload_filesystems()
733 {
734 if (ebpf_modules[EBPF_MODULE_FILESYSTEM_IDX].enabled == NETDATA_THREAD_EBPF_NOT_RUNNING ||
701 - ebpf_modules[EBPF_MODULE_FILESYSTEM_IDX].enabled == NETDATA_THREAD_EBPF_RUNNING ||
735 + ebpf_modules[EBPF_MODULE_FILESYSTEM_IDX].enabled < NETDATA_THREAD_EBPF_STOPPING ||
736 ebpf_modules[EBPF_MODULE_FILESYSTEM_IDX].load != EBPF_LOAD_LEGACY)
737 return;
738
@@ -719,7 +753,7 @@ static void ebpf_unload_filesystems()
753 static void ebpf_unload_sync()
754 {
755 if (ebpf_modules[EBPF_MODULE_SYNC_IDX].enabled == NETDATA_THREAD_EBPF_NOT_RUNNING ||
722 - ebpf_modules[EBPF_MODULE_SYNC_IDX].enabled == NETDATA_THREAD_EBPF_RUNNING)
756 + ebpf_modules[EBPF_MODULE_SYNC_IDX].enabled < NETDATA_THREAD_EBPF_STOPPING)
757 return;
758
759 int i;
@@ -757,7 +791,7 @@ static void ebpf_stop_threads(int sig)
791 only_one = 1;
792 int i;
793 for (i = 0; ebpf_modules[i].thread_name != NULL; i++) {
760 - if (ebpf_modules[i].enabled == NETDATA_THREAD_EBPF_RUNNING) {
794 + if (ebpf_modules[i].enabled < NETDATA_THREAD_EBPF_STOPPING) {
795 netdata_thread_cancel(*ebpf_modules[i].thread->thread);
796 #ifdef NETDATA_DEV_MODE
797 netdata_log_info("Sending cancel for thread %s", ebpf_modules[i].thread_name);
@@ -792,6 +826,19 @@ static void ebpf_stop_threads(int sig)
826 *
827 *****************************************************************/
828
829 +/**
830 + * Create apps for module
831 + *
832 + * Create apps chart that will be used with specific module
833 + *
834 + * @param em the module main structure.
835 + * @param root a pointer for the targets.
836 + */
837 +static inline void ebpf_create_apps_for_module(ebpf_module_t *em, struct ebpf_target *root) {
838 + if (em->enabled < NETDATA_THREAD_EBPF_STOPPING && em->apps_charts && em->apps_routine)
839 + em->apps_routine(em, root);
840 +}
841 +
842 /**
843 * Create apps charts
844 *
@@ -833,14 +880,21 @@ static void ebpf_create_apps_charts(struct ebpf_target *root)
880 }
881 }
882
836 - if (!newly_added)
883 + int i;
884 + if (!newly_added) {
885 + for (i = 0; i < EBPF_MODULE_FUNCTION_IDX ; i++) {
886 + ebpf_module_t *current = &ebpf_modules[i];
887 + if (current->apps_charts & NETDATA_EBPF_APPS_FLAG_CHART_CREATED)
888 + continue;
889 +
890 + ebpf_create_apps_for_module(current, root);
891 + }
892 return;
893 + }
894
839 - int counter;
840 - for (counter = 0; ebpf_modules[counter].thread_name; counter++) {
841 - ebpf_module_t *current = &ebpf_modules[counter];
842 - if (current->enabled == NETDATA_THREAD_EBPF_RUNNING && current->apps_charts && current->apps_routine)
843 - current->apps_routine(current, root);
895 + for (i = 0; i < EBPF_MODULE_FUNCTION_IDX ; i++) {
896 + ebpf_module_t *current = &ebpf_modules[i];
897 + ebpf_create_apps_for_module(current, root);
898 }
899 }
900
@@ -1169,7 +1223,7 @@ void write_histogram_chart(char *family, char *name, const netdata_idx_t *hist,
1223 * @param name the name used to create aral
1224 * @param em a pointer to the structure with the default values.
1225 */
1172 -void ebpf_statistic_create_aral_chart(char *name, ebpf_module_t *em)
1226 +int ebpf_statistic_create_aral_chart(char *name, ebpf_module_t *em)
1227 {
1228 static int priority = 140100;
1229 char *mem = { NETDATA_EBPF_STAT_DIMENSION_MEMORY };
@@ -1207,6 +1261,40 @@ void ebpf_statistic_create_aral_chart(char *name, ebpf_module_t *em)
1261 ebpf_write_global_dimension(aral,
1262 aral,
1263 ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
1264 +
1265 + return priority - 2;
1266 +}
1267 +
1268 +/**
1269 + * ARAL Charts
1270 + *
1271 + * Add chart to monitor ARAL usage
1272 + * Caller must call this function with mutex locked.
1273 + *
1274 + * @param em a pointer to the structure with the default values.
1275 + * @param prio the initial priority used to disable charts.
1276 + */
1277 +void ebpf_statistic_obsolete_aral_chart(ebpf_module_t *em, int prio)
1278 +{
1279 + ebpf_write_chart_obsolete(NETDATA_MONITORING_FAMILY,
1280 + em->memory_allocations,
1281 + "Calls to allocate memory.",
1282 + "calls",
1283 + NETDATA_EBPF_FAMILY,
1284 + NETDATA_EBPF_CHART_TYPE_STACKED,
1285 + "netdata.ebpf_aral_stat_alloc",
1286 + prio++,
1287 + em->update_every);
1288 +
1289 + ebpf_write_chart_obsolete(NETDATA_MONITORING_FAMILY,
1290 + em->memory_allocations,
1291 + "Calls to allocate memory.",
1292 + "calls",
1293 + NETDATA_EBPF_FAMILY,
1294 + NETDATA_EBPF_CHART_TYPE_STACKED,
1295 + "netdata.ebpf_aral_stat_alloc",
1296 + prio++,
1297 + em->update_every);
1298 }
1299
1300 /**
@@ -1280,7 +1368,7 @@ void ebpf_global_labels(netdata_syscall_stat_t *is, netdata_publish_syscall_t *p
1368 static inline void ebpf_set_thread_mode(netdata_run_mode_t lmode)
1369 {
1370 int i;
1283 - for (i = 0; ebpf_modules[i].thread_name; i++) {
1371 + for (i = 0; i < EBPF_MODULE_FUNCTION_IDX; i++) {
1372 ebpf_modules[i].mode = lmode;
1373 }
1374 }
@@ -1289,16 +1377,15 @@ static inline void ebpf_set_thread_mode(netdata_run_mode_t lmode)
1377 * Enable specific charts selected by user.
1378 *
1379 * @param em the structure that will be changed
1292 - * @param disable_apps the status about the apps charts.
1380 * @param disable_cgroup the status about the cgroups charts.
1381 */
1295 -static inline void ebpf_enable_specific_chart(struct ebpf_module *em, int disable_apps, int disable_cgroup)
1382 +static inline void ebpf_enable_specific_chart(struct ebpf_module *em, int disable_cgroup)
1383 {
1384 em->enabled = CONFIG_BOOLEAN_YES;
1385
1386 // oomkill stores data inside apps submenu, so it always need to have apps_enabled for plugin to create
1387 // its chart, without this comparison eBPF.plugin will try to store invalid data when apps is disabled.
1301 - if (!disable_apps || !strcmp(em->thread_name, "oomkill")) {
1388 + if (!strcmp(em->thread_name, "oomkill")) {
1389 em->apps_charts = NETDATA_EBPF_APPS_FLAG_YES;
1390 }
1391
@@ -1309,20 +1396,6 @@ static inline void ebpf_enable_specific_chart(struct ebpf_module *em, int disabl
1396 em->global_charts = CONFIG_BOOLEAN_YES;
1397 }
1398
1312 -/**
1313 - * Enable all charts
1314 - *
1315 - * @param apps what is the current status of apps
1316 - * @param cgroups what is the current status of cgroups
1317 - */
1318 -static inline void ebpf_enable_all_charts(int apps, int cgroups)
1319 -{
1320 - int i;
1321 - for (i = 0; ebpf_modules[i].thread_name; i++) {
1322 - ebpf_enable_specific_chart(&ebpf_modules[i], apps, cgroups);
1323 - }
1324 -}
1325 -
1399 /**
1400 * Disable all Global charts
1401 *
@@ -1337,37 +1410,22 @@ static inline void disable_all_global_charts()
1410 }
1411 }
1412
1340 -
1413 /**
1414 * Enable the specified chart group
1415 *
1416 * @param idx the index of ebpf_modules that I am enabling
1345 - * @param disable_apps should I keep apps charts?
1417 */
1347 -static inline void ebpf_enable_chart(int idx, int disable_apps, int disable_cgroup)
1418 +static inline void ebpf_enable_chart(int idx, int disable_cgroup)
1419 {
1420 int i;
1421 for (i = 0; ebpf_modules[i].thread_name; i++) {
1422 if (i == idx) {
1352 - ebpf_enable_specific_chart(&ebpf_modules[i], disable_apps, disable_cgroup);
1423 + ebpf_enable_specific_chart(&ebpf_modules[i], disable_cgroup);
1424 break;
1425 }
1426 }
1427 }
1428
1358 -/**
1359 - * Disable APPs
1360 - *
1361 - * Disable charts for apps loading only global charts.
1362 - */
1363 -static inline void ebpf_disable_apps()
1364 -{
1365 - int i;
1366 - for (i = 0; ebpf_modules[i].thread_name; i++) {
1367 - ebpf_modules[i].apps_charts = NETDATA_EBPF_APPS_FLAG_NO;
1368 - }
1369 -}
1370 -
1429 /**
1430 * Disable Cgroups
1431 *
@@ -1670,33 +1728,11 @@ void ebpf_start_pthread_variables()
1728 pthread_mutex_init(&mutex_cgroup_shm, NULL);
1729 }
1730
1673 -/**
1674 - * Am I collecting PIDs?
1675 - *
1676 - * Test if eBPF plugin needs to collect PID information.
1677 - *
1678 - * @return It returns 1 if at least one thread needs to collect the data, or zero otherwise.
1679 - */
1680 -static inline uint32_t ebpf_am_i_collect_pids()
1681 -{
1682 - uint32_t ret = 0;
1683 - int i;
1684 - for (i = 0; ebpf_modules[i].thread_name; i++) {
1685 - ret |= ebpf_modules[i].cgroup_charts | (ebpf_modules[i].apps_charts & NETDATA_EBPF_APPS_FLAG_YES);
1686 - }
1687 -
1688 - return ret;
1689 -}
1690 -
1731 /**
1732 * Allocate the vectors used for all threads.
1733 */
1734 static void ebpf_allocate_common_vectors()
1735 {
1696 - if (unlikely(!ebpf_am_i_collect_pids())) {
1697 - return;
1698 - }
1699 -
1736 ebpf_all_pids = callocz((size_t)pid_max, sizeof(struct ebpf_pid_stat *));
1737 ebpf_aral_init();
1738 }
@@ -1706,7 +1742,7 @@ static void ebpf_allocate_common_vectors()
1742 *
1743 * @param ptr the option given by users
1744 */
1709 -static inline void how_to_load(char *ptr)
1745 +static inline void ebpf_how_to_load(char *ptr)
1746 {
1747 if (!strcasecmp(ptr, EBPF_CFG_LOAD_MODE_RETURN))
1748 ebpf_set_thread_mode(MODE_RETURN);
@@ -1716,6 +1752,20 @@ static inline void how_to_load(char *ptr)
1752 netdata_log_error("the option %s for \"ebpf load mode\" is not a valid option.", ptr);
1753 }
1754
1755 +/**
1756 + * Define whether we should have charts for apps
1757 + *
1758 + * @param lmode the mode that will be used for them.
1759 + */
1760 +static inline void ebpf_set_apps_mode(netdata_apps_integration_flags_t value)
1761 +{
1762 + int i;
1763 + for (i = 0; i < EBPF_MODULE_FUNCTION_IDX; i++) {
1764 + ebpf_modules[i].apps_charts = value;
1765 + }
1766 +}
1767 +
1768 +
1769 /**
1770 * Update interval
1771 *
@@ -1748,6 +1798,21 @@ static void ebpf_update_table_size()
1798 }
1799 }
1800
1801 +/**
1802 + * Update lifetime
1803 + *
1804 + * Update the period of time that specific thread will run
1805 + */
1806 +static void ebpf_update_lifetime()
1807 +{
1808 + int i;
1809 + uint32_t value = (uint32_t) appconfig_get_number(&collector_config, EBPF_GLOBAL_SECTION,
1810 + EBPF_CFG_LIFETIME, EBPF_DEFAULT_LIFETIME);
1811 + for (i = 0; ebpf_modules[i].thread_name; i++) {
1812 + ebpf_modules[i].lifetime = value;
1813 + }
1814 +}
1815 +
1816 /**
1817 * Set Load mode
1818 *
@@ -1793,12 +1858,11 @@ static void ebpf_update_map_per_core()
1858 /**
1859 * Read collector values
1860 *
1796 - * @param disable_apps variable to store information related to apps.
1861 * @param disable_cgroups variable to store information related to cgroups.
1862 * @param update_every value to overwrite the update frequency set by the server.
1863 * @param origin specify the configuration file loaded
1864 */
1801 -static void read_collector_values(int *disable_apps, int *disable_cgroups,
1865 +static void read_collector_values(int *disable_cgroups,
1866 int update_every, netdata_ebpf_load_mode_t origin)
1867 {
1868 // Read global section
@@ -1810,7 +1874,7 @@ static void read_collector_values(int *disable_apps, int *disable_cgroups,
1874 value = appconfig_get(&collector_config, EBPF_GLOBAL_SECTION, EBPF_CFG_LOAD_MODE,
1875 EBPF_CFG_LOAD_MODE_DEFAULT);
1876
1813 - how_to_load(value);
1877 + ebpf_how_to_load(value);
1878
1879 btf_path = appconfig_get(&collector_config, EBPF_GLOBAL_SECTION, EBPF_CFG_PROGRAM_PATH,
1880 EBPF_DEFAULT_BTF_PATH);
@@ -1827,6 +1891,8 @@ static void read_collector_values(int *disable_apps, int *disable_cgroups,
1891
1892 ebpf_update_table_size();
1893
1894 + ebpf_update_lifetime();
1895 +
1896 // This is kept to keep compatibility
1897 uint32_t enabled = appconfig_get_boolean(&collector_config, EBPF_GLOBAL_SECTION, "disable apps",
1898 CONFIG_BOOLEAN_NO);
@@ -1836,7 +1902,8 @@ static void read_collector_values(int *disable_apps, int *disable_cgroups,
1902 CONFIG_BOOLEAN_YES);
1903 enabled = (enabled == CONFIG_BOOLEAN_NO)?CONFIG_BOOLEAN_YES:CONFIG_BOOLEAN_NO;
1904 }
1839 - *disable_apps = (int)enabled;
1905 +
1906 + ebpf_set_apps_mode(!enabled);
1907
1908 // Cgroup is a positive sentence, so we need to invert the values to disable apps.
1909 // We are using the same pattern for cgroup and apps
@@ -1848,10 +1915,8 @@ static void read_collector_values(int *disable_apps, int *disable_cgroups,
1915 // Read ebpf programs section
1916 enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION,
1917 ebpf_modules[EBPF_MODULE_PROCESS_IDX].config_name, CONFIG_BOOLEAN_YES);
1851 - int started = 0;
1918 if (enabled) {
1853 - ebpf_enable_chart(EBPF_MODULE_PROCESS_IDX, *disable_apps, *disable_cgroups);
1854 - started++;
1919 + ebpf_enable_chart(EBPF_MODULE_PROCESS_IDX, *disable_cgroups);
1920 }
1921
1922 // This is kept to keep compatibility
@@ -1862,8 +1927,7 @@ static void read_collector_values(int *disable_apps, int *disable_cgroups,
1927 ebpf_modules[EBPF_MODULE_SOCKET_IDX].config_name,
1928 CONFIG_BOOLEAN_NO);
1929 if (enabled) {
1865 - ebpf_enable_chart(EBPF_MODULE_SOCKET_IDX, *disable_apps, *disable_cgroups);
1866 - started++;
1930 + ebpf_enable_chart(EBPF_MODULE_SOCKET_IDX, *disable_cgroups);
1931 }
1932
1933 // This is kept to keep compatibility
@@ -1875,123 +1939,98 @@ static void read_collector_values(int *disable_apps, int *disable_cgroups,
1939 network_viewer_opt.enabled = enabled;
1940 if (enabled) {
1941 if (!ebpf_modules[EBPF_MODULE_SOCKET_IDX].enabled)
1878 - ebpf_enable_chart(EBPF_MODULE_SOCKET_IDX, *disable_apps, *disable_cgroups);
1942 + ebpf_enable_chart(EBPF_MODULE_SOCKET_IDX, *disable_cgroups);
1943
1944 // Read network viewer section if network viewer is enabled
1945 // This is kept here to keep backward compatibility
1946 parse_network_viewer_section(&collector_config);
1947 parse_service_name_section(&collector_config);
1884 - started++;
1948 }
1949
1950 enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "cachestat",
1951 CONFIG_BOOLEAN_NO);
1952
1953 if (enabled) {
1891 - ebpf_enable_chart(EBPF_MODULE_CACHESTAT_IDX, *disable_apps, *disable_cgroups);
1892 - started++;
1954 + ebpf_enable_chart(EBPF_MODULE_CACHESTAT_IDX, *disable_cgroups);
1955 }
1956
1957 enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "sync",
1958 CONFIG_BOOLEAN_YES);
1959
1960 if (enabled) {
1899 - ebpf_enable_chart(EBPF_MODULE_SYNC_IDX, *disable_apps, *disable_cgroups);
1900 - started++;
1961 + ebpf_enable_chart(EBPF_MODULE_SYNC_IDX, *disable_cgroups);
1962 }
1963
1964 enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "dcstat",
1965 CONFIG_BOOLEAN_NO);
1966 if (enabled) {
1906 - ebpf_enable_chart(EBPF_MODULE_DCSTAT_IDX, *disable_apps, *disable_cgroups);
1907 - started++;
1967 + ebpf_enable_chart(EBPF_MODULE_DCSTAT_IDX, *disable_cgroups);
1968 }
1969
1970 enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "swap",
1971 CONFIG_BOOLEAN_NO);
1972 if (enabled) {
1913 - ebpf_enable_chart(EBPF_MODULE_SWAP_IDX, *disable_apps, *disable_cgroups);
1914 - started++;
1973 + ebpf_enable_chart(EBPF_MODULE_SWAP_IDX, *disable_cgroups);
1974 }
1975
1976 enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "vfs",
1977 CONFIG_BOOLEAN_NO);
1978 if (enabled) {
1920 - ebpf_enable_chart(EBPF_MODULE_VFS_IDX, *disable_apps, *disable_cgroups);
1921 - started++;
1979 + ebpf_enable_chart(EBPF_MODULE_VFS_IDX, *disable_cgroups);
1980 }
1981
1982 enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "filesystem",
1983 CONFIG_BOOLEAN_NO);
1984 if (enabled) {
1927 - ebpf_enable_chart(EBPF_MODULE_FILESYSTEM_IDX, *disable_apps, *disable_cgroups);
1928 - started++;
1985 + ebpf_enable_chart(EBPF_MODULE_FILESYSTEM_IDX, *disable_cgroups);
1986 }
1987
1988 enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "disk",
1989 CONFIG_BOOLEAN_NO);
1990 if (enabled) {
1934 - ebpf_enable_chart(EBPF_MODULE_DISK_IDX, *disable_apps, *disable_cgroups);
1935 - started++;
1991 + ebpf_enable_chart(EBPF_MODULE_DISK_IDX, *disable_cgroups);
1992 }
1993
1994 enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "mount",
1995 CONFIG_BOOLEAN_YES);
1996 if (enabled) {
1941 - ebpf_enable_chart(EBPF_MODULE_MOUNT_IDX, *disable_apps, *disable_cgroups);
1942 - started++;
1997 + ebpf_enable_chart(EBPF_MODULE_MOUNT_IDX, *disable_cgroups);
1998 }
1999
2000 enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "fd",
2001 CONFIG_BOOLEAN_YES);
2002 if (enabled) {
1948 - ebpf_enable_chart(EBPF_MODULE_FD_IDX, *disable_apps, *disable_cgroups);
1949 - started++;
2003 + ebpf_enable_chart(EBPF_MODULE_FD_IDX, *disable_cgroups);
2004 }
2005
2006 enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "hardirq",
2007 CONFIG_BOOLEAN_YES);
2008 if (enabled) {
1955 - ebpf_enable_chart(EBPF_MODULE_HARDIRQ_IDX, *disable_apps, *disable_cgroups);
1956 - started++;
2009 + ebpf_enable_chart(EBPF_MODULE_HARDIRQ_IDX, *disable_cgroups);
2010 }
2011
2012 enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "softirq",
2013 CONFIG_BOOLEAN_YES);
2014 if (enabled) {
1962 - ebpf_enable_chart(EBPF_MODULE_SOFTIRQ_IDX, *disable_apps, *disable_cgroups);
1963 - started++;
2015 + ebpf_enable_chart(EBPF_MODULE_SOFTIRQ_IDX, *disable_cgroups);
2016 }
2017
2018 enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "oomkill",
2019 CONFIG_BOOLEAN_YES);
2020 if (enabled) {
1969 - ebpf_enable_chart(EBPF_MODULE_OOMKILL_IDX, *disable_apps, *disable_cgroups);
1970 - started++;
2021 + ebpf_enable_chart(EBPF_MODULE_OOMKILL_IDX, *disable_cgroups);
2022 }
2023
2024 enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "shm",
2025 CONFIG_BOOLEAN_YES);
2026 if (enabled) {
1976 - ebpf_enable_chart(EBPF_MODULE_SHM_IDX, *disable_apps, *disable_cgroups);
1977 - started++;
2027 + ebpf_enable_chart(EBPF_MODULE_SHM_IDX, *disable_cgroups);
2028 }
2029
2030 enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "mdflush",
2031 CONFIG_BOOLEAN_NO);
2032 if (enabled) {
1983 - ebpf_enable_chart(EBPF_MODULE_MDFLUSH_IDX, *disable_apps, *disable_cgroups);
1984 - started++;
1985 - }
1986 -
1987 - if (!started){
1988 - ebpf_enable_all_charts(*disable_apps, *disable_cgroups);
1989 - // Read network viewer section
1990 - // This is kept here to keep backward compatibility
1991 - if (network_viewer_opt.enabled) {
1992 - parse_network_viewer_section(&collector_config);
1993 - parse_service_name_section(&collector_config);
1994 - }
2033 + ebpf_enable_chart(EBPF_MODULE_MDFLUSH_IDX, *disable_cgroups);
2034 }
2035 }
2036
@@ -1999,13 +2038,12 @@ static void read_collector_values(int *disable_apps, int *disable_cgroups,
2038 * Load collector config
2039 *
2040 * @param path the path where the file ebpf.conf is stored.
2002 - * @param disable_apps variable to store the information about apps plugin status.
2041 * @param disable_cgroups variable to store the information about cgroups plugin status.
2042 * @param update_every value to overwrite the update frequency set by the server.
2043 *
2044 * @return 0 on success and -1 otherwise.
2045 */
2008 -static int load_collector_config(char *path, int *disable_apps, int *disable_cgroups, int update_every)
2046 +static int ebpf_load_collector_config(char *path, int *disable_cgroups, int update_every)
2047 {
2048 char lpath[4096];
2049 netdata_ebpf_load_mode_t origin;
@@ -2020,7 +2058,7 @@ static int load_collector_config(char *path, int *disable_apps, int *disable_cgr
2058 } else
2059 origin = EBPF_LOADED_FROM_USER;
2060
2023 - read_collector_values(disable_apps, disable_cgroups, update_every, origin);
2061 + read_collector_values(disable_cgroups, update_every, origin);
2062
2063 return 0;
2064 }
@@ -2064,7 +2102,7 @@ void set_global_variables()
2102 static inline void ebpf_load_thread_config()
2103 {
2104 int i;
2067 - for (i = 0; ebpf_modules[i].thread_name; i++) {
2105 + for (i = 0; i < EBPF_MODULE_FUNCTION_IDX; i++) {
2106 ebpf_update_module(&ebpf_modules[i], default_btf, running_on_kernel, isrh);
2107 }
2108 }
@@ -2119,7 +2157,6 @@ int ebpf_adjust_memory_limit()
2157 */
2158 static void ebpf_parse_args(int argc, char **argv)
2159 {
2122 - int disable_apps = 0;
2160 int disable_cgroups = 1;
2161 int freq = 0;
2162 int option_index = 0;
@@ -2166,11 +2203,11 @@ static void ebpf_parse_args(int argc, char **argv)
2203 if (!freq)
2204 freq = EBPF_DEFAULT_UPDATE_EVERY;
2205
2169 - if (load_collector_config(ebpf_user_config_dir, &disable_apps, &disable_cgroups, freq)) {
2206 + if (ebpf_load_collector_config(ebpf_user_config_dir, &disable_cgroups, freq)) {
2207 netdata_log_info(
2208 "Does not have a configuration file inside `%s/ebpf.d.conf. It will try to load stock file.",
2209 ebpf_user_config_dir);
2173 - if (load_collector_config(ebpf_stock_config_dir, &disable_apps, &disable_cgroups, freq)) {
2210 + if (ebpf_load_collector_config(ebpf_stock_config_dir, &disable_cgroups, freq)) {
2211 netdata_log_info("Does not have a stock file. It is starting with default options.");
2212 }
2213 }
@@ -2296,7 +2333,7 @@ static void ebpf_parse_args(int argc, char **argv)
2333 break;
2334 }
2335 case EBPF_OPTION_ALL_CHARTS: {
2299 - disable_apps = 0;
2336 + ebpf_set_apps_mode(NETDATA_EBPF_APPS_FLAG_YES);
2337 disable_cgroups = 0;
2338 #ifdef NETDATA_INTERNAL_CHECKS
2339 netdata_log_info("EBPF running with all chart groups, because it was started with the option \"[-]-all\".");
@@ -2312,7 +2349,6 @@ static void ebpf_parse_args(int argc, char **argv)
2349 exit(0);
2350 }
2351 case EBPF_OPTION_GLOBAL_CHART: {
2315 - disable_apps = 1;
2352 disable_cgroups = 1;
2353 #ifdef NETDATA_INTERNAL_CHECKS
2354 netdata_log_info("EBPF running with global chart group, because it was started with the option \"[-]-global\".");
@@ -2373,10 +2409,7 @@ unittest:
2409 }
2410 }
2411
2376 - if (disable_apps || disable_cgroups) {
2377 - if (disable_apps)
2378 - ebpf_disable_apps();
2379 -
2412 + if (disable_cgroups) {
2413 if (disable_cgroups)
2414 ebpf_disable_cgroups();
2415 }
@@ -2386,7 +2419,7 @@ unittest:
2419 uint64_t idx;
2420 for (idx = 0; idx < EBPF_OPTION_ALL_CHARTS; idx++) {
2421 if (select_threads & 1<<idx)
2389 - ebpf_enable_specific_chart(&ebpf_modules[idx], disable_apps, disable_cgroups);
2422 + ebpf_enable_specific_chart(&ebpf_modules[idx], disable_cgroups);
2423 }
2424 }
2425
@@ -2405,6 +2438,280 @@ unittest:
2438 netdata_log_info("Loaded config file '%s/apps_groups.conf'", ebpf_user_config_dir);
2439 }
2440
2441 +/*****************************************************************
2442 + *
2443 + * Collector charts
2444 + *
2445 + *****************************************************************/
2446 +
2447 +static char *load_event_stat[NETDATA_EBPF_LOAD_STAT_END] = {"legacy", "co-re"};
2448 +static char *memlock_stat = {"memory_locked"};
2449 +static char *hash_table_stat = {"hash_table"};
2450 +static char *hash_table_core[NETDATA_EBPF_LOAD_STAT_END] = {"per_core", "unique"};
2451 +
2452 +/**
2453 + * Send Statistic Data
2454 + *
2455 + * Send statistic information to netdata.
2456 + */
2457 +void ebpf_send_statistic_data()
2458 +{
2459 + if (!publish_internal_metrics)
2460 + return;
2461 +
2462 + write_begin_chart(NETDATA_MONITORING_FAMILY, NETDATA_EBPF_THREADS);
2463 + int i;
2464 + for (i = 0; i < EBPF_MODULE_FUNCTION_IDX; i++) {
2465 + ebpf_module_t *wem = &ebpf_modules[i];
2466 + write_chart_dimension((char *)wem->thread_name, (wem->enabled < NETDATA_THREAD_EBPF_STOPPING) ? 1 : 0);
2467 + }
2468 + write_end_chart();
2469 +
2470 + write_begin_chart(NETDATA_MONITORING_FAMILY, NETDATA_EBPF_LIFE_TIME);
2471 + for (i = 0; i < EBPF_MODULE_FUNCTION_IDX ; i++) {
2472 + ebpf_module_t *wem = &ebpf_modules[i];
2473 + // Threads like VFS is slow to load and this can create an invalid number, this is the motive
2474 + // we are also testing wem->lifetime value.
2475 + write_chart_dimension((char *)wem->thread_name,
2476 + (wem->lifetime && wem->enabled < NETDATA_THREAD_EBPF_STOPPING) ?
2477 + (long long) (wem->lifetime - wem->running_time):
2478 + 0) ;
2479 + }
2480 + write_end_chart();
2481 +
2482 + write_begin_chart(NETDATA_MONITORING_FAMILY, NETDATA_EBPF_LOAD_METHOD);
2483 + write_chart_dimension(load_event_stat[NETDATA_EBPF_LOAD_STAT_LEGACY], (long long)plugin_statistics.legacy);
2484 + write_chart_dimension(load_event_stat[NETDATA_EBPF_LOAD_STAT_CORE], (long long)plugin_statistics.core);
2485 + write_end_chart();
2486 +
2487 + write_begin_chart(NETDATA_MONITORING_FAMILY, NETDATA_EBPF_KERNEL_MEMORY);
2488 + write_chart_dimension(memlock_stat, (long long)plugin_statistics.memlock_kern);
2489 + write_end_chart();
2490 +
2491 + write_begin_chart(NETDATA_MONITORING_FAMILY, NETDATA_EBPF_HASH_TABLES_LOADED);
2492 + write_chart_dimension(hash_table_stat, (long long)plugin_statistics.hash_tables);
2493 + write_end_chart();
2494 +
2495 + write_begin_chart(NETDATA_MONITORING_FAMILY, NETDATA_EBPF_HASH_TABLES_PER_CORE);
2496 + write_chart_dimension(hash_table_core[NETDATA_EBPF_THREAD_PER_CORE], (long long)plugin_statistics.hash_percpu);
2497 + write_chart_dimension(hash_table_core[NETDATA_EBPF_THREAD_UNIQUE], (long long)plugin_statistics.hash_unique);
2498 + write_end_chart();
2499 +}
2500 +
2501 +/**
2502 + * Update Internal Metric variable
2503 + *
2504 + * By default eBPF.plugin sends internal metrics for netdata, but user can
2505 + * disable this.
2506 + *
2507 + * The function updates the variable used to send charts.
2508 + */
2509 +static void update_internal_metric_variable()
2510 +{
2511 + const char *s = getenv("NETDATA_INTERNALS_MONITORING");
2512 + if (s && *s && strcmp(s, "NO") == 0)
2513 + publish_internal_metrics = false;
2514 +}
2515 +
2516 +/**
2517 + * Create chart for Statistic Thread
2518 + *
2519 + * Write to standard output current values for threads.
2520 + *
2521 + * @param update_every time used to update charts
2522 + */
2523 +static inline void ebpf_create_statistic_thread_chart(int update_every)
2524 +{
2525 + ebpf_write_chart_cmd(NETDATA_MONITORING_FAMILY,
2526 + NETDATA_EBPF_THREADS,
2527 + "Threads running.",
2528 + "boolean",
2529 + NETDATA_EBPF_FAMILY,
2530 + NETDATA_EBPF_CHART_TYPE_LINE,
2531 + NULL,
2532 + NETDATA_EBPF_ORDER_STAT_THREADS,
2533 + update_every,
2534 + NETDATA_EBPF_MODULE_NAME_PROCESS);
2535 +
2536 + int i;
2537 + for (i = 0; i < EBPF_MODULE_FUNCTION_IDX; i++) {
2538 + ebpf_write_global_dimension((char *)ebpf_modules[i].thread_name,
2539 + (char *)ebpf_modules[i].thread_name,
2540 + ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
2541 + }
2542 +}
2543 +
2544 +/**
2545 + * Create lifetime Thread Chart
2546 + *
2547 + * Write to standard output current values for threads lifetime.
2548 + *
2549 + * @param update_every time used to update charts
2550 + */
2551 +static inline void ebpf_create_lifetime_thread_chart(int update_every)
2552 +{
2553 + ebpf_write_chart_cmd(NETDATA_MONITORING_FAMILY,
2554 + NETDATA_EBPF_LIFE_TIME,
2555 + "Threads running.",
2556 + "seconds",
2557 + NETDATA_EBPF_FAMILY,
2558 + NETDATA_EBPF_CHART_TYPE_LINE,
2559 + NULL,
2560 + NETDATA_EBPF_ORDER_STAT_LIFE_TIME,
2561 + update_every,
2562 + NETDATA_EBPF_MODULE_NAME_PROCESS);
2563 +
2564 + int i;
2565 + for (i = 0; i < EBPF_MODULE_FUNCTION_IDX; i++) {
2566 + ebpf_write_global_dimension((char *)ebpf_modules[i].thread_name,
2567 + (char *)ebpf_modules[i].thread_name,
2568 + ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
2569 + }
2570 +}
2571 +
2572 +/**
2573 + * Create chart for Load Thread
2574 + *
2575 + * Write to standard output current values for load mode.
2576 + *
2577 + * @param update_every time used to update charts
2578 + */
2579 +static inline void ebpf_create_statistic_load_chart(int update_every)
2580 +{
2581 + ebpf_write_chart_cmd(NETDATA_MONITORING_FAMILY,
2582 + NETDATA_EBPF_LOAD_METHOD,
2583 + "Load info.",
2584 + "methods",
2585 + NETDATA_EBPF_FAMILY,
2586 + NETDATA_EBPF_CHART_TYPE_LINE,
2587 + NULL,
2588 + NETDATA_EBPF_ORDER_STAT_LOAD_METHOD,
2589 + update_every,
2590 + NETDATA_EBPF_MODULE_NAME_PROCESS);
2591 +
2592 + ebpf_write_global_dimension(load_event_stat[NETDATA_EBPF_LOAD_STAT_LEGACY],
2593 + load_event_stat[NETDATA_EBPF_LOAD_STAT_LEGACY],
2594 + ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
2595 +
2596 + ebpf_write_global_dimension(load_event_stat[NETDATA_EBPF_LOAD_STAT_CORE],
2597 + load_event_stat[NETDATA_EBPF_LOAD_STAT_CORE],
2598 + ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
2599 +}
2600 +
2601 +/**
2602 + * Create chart for Kernel Memory
2603 + *
2604 + * Write to standard output current values for allocated memory.
2605 + *
2606 + * @param update_every time used to update charts
2607 + */
2608 +static inline void ebpf_create_statistic_kernel_memory(int update_every)
2609 +{
2610 + ebpf_write_chart_cmd(NETDATA_MONITORING_FAMILY,
2611 + NETDATA_EBPF_KERNEL_MEMORY,
2612 + "Memory allocated for hash tables.",
2613 + "bytes",
2614 + NETDATA_EBPF_FAMILY,
2615 + NETDATA_EBPF_CHART_TYPE_LINE,
2616 + NULL,
2617 + NETDATA_EBPF_ORDER_STAT_KERNEL_MEMORY,
2618 + update_every,
2619 + NETDATA_EBPF_MODULE_NAME_PROCESS);
2620 +
2621 + ebpf_write_global_dimension(memlock_stat,
2622 + memlock_stat,
2623 + ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
2624 +}
2625 +
2626 +/**
2627 + * Create chart Hash Table
2628 + *
2629 + * Write to standard output number of hash tables used with this software.
2630 + *
2631 + * @param update_every time used to update charts
2632 + */
2633 +static inline void ebpf_create_statistic_hash_tables(int update_every)
2634 +{
2635 + ebpf_write_chart_cmd(NETDATA_MONITORING_FAMILY,
2636 + NETDATA_EBPF_HASH_TABLES_LOADED,
2637 + "Number of hash tables loaded.",
2638 + "hash tables",
2639 + NETDATA_EBPF_FAMILY,
2640 + NETDATA_EBPF_CHART_TYPE_LINE,
2641 + NULL,
2642 + NETDATA_EBPF_ORDER_STAT_HASH_TABLES,
2643 + update_every,
2644 + NETDATA_EBPF_MODULE_NAME_PROCESS);
2645 +
2646 + ebpf_write_global_dimension(hash_table_stat,
2647 + hash_table_stat,
2648 + ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
2649 +}
2650 +
2651 +/**
2652 + * Create chart for percpu stats
2653 + *
2654 + * Write to standard output current values for threads.
2655 + *
2656 + * @param update_every time used to update charts
2657 + */
2658 +static inline void ebpf_create_statistic_hash_per_core(int update_every)
2659 +{
2660 + ebpf_write_chart_cmd(NETDATA_MONITORING_FAMILY,
2661 + NETDATA_EBPF_HASH_TABLES_PER_CORE,
2662 + "How threads are loading hash/array tables.",
2663 + "threads",
2664 + NETDATA_EBPF_FAMILY,
2665 + NETDATA_EBPF_CHART_TYPE_LINE,
2666 + NULL,
2667 + NETDATA_EBPF_ORDER_STAT_HASH_CORE,
2668 + update_every,
2669 + NETDATA_EBPF_MODULE_NAME_PROCESS);
2670 +
2671 + ebpf_write_global_dimension(hash_table_core[NETDATA_EBPF_THREAD_PER_CORE],
2672 + hash_table_core[NETDATA_EBPF_THREAD_PER_CORE],
2673 + ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
2674 +
2675 + ebpf_write_global_dimension(hash_table_core[NETDATA_EBPF_THREAD_UNIQUE],
2676 + hash_table_core[NETDATA_EBPF_THREAD_UNIQUE],
2677 + ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
2678 +}
2679 +
2680 +
2681 +/**
2682 + * Create Statistics Charts
2683 + *
2684 + * Create charts that will show statistics related to eBPF plugin.
2685 + *
2686 + * @param update_every time used to update charts
2687 + */
2688 +static void ebpf_create_statistic_charts(int update_every)
2689 +{
2690 + static char create_charts = 1;
2691 + update_internal_metric_variable();
2692 + if (!publish_internal_metrics)
2693 + return;
2694 +
2695 + if (!create_charts)
2696 + return;
2697 +
2698 + create_charts = 0;
2699 +
2700 + ebpf_create_statistic_thread_chart(update_every);
2701 + EBPF_PLUGIN_FUNCTIONS(EBPF_FUNCTION_THREAD, EBPF_PLUGIN_THREAD_FUNCTION_DESCRIPTION);
2702 +
2703 + ebpf_create_lifetime_thread_chart(update_every);
2704 + EBPF_PLUGIN_FUNCTIONS(EBPF_FUNCTION_THREAD, EBPF_PLUGIN_THREAD_FUNCTION_DESCRIPTION);
2705 +
2706 + ebpf_create_statistic_load_chart(update_every);
2707 +
2708 + ebpf_create_statistic_kernel_memory(update_every);
2709 +
2710 + ebpf_create_statistic_hash_tables(update_every);
2711 +
2712 + ebpf_create_statistic_hash_per_core(update_every);
2713 +}
2714 +
2715 /*****************************************************************
2716 *
2717 * COLLECTOR ENTRY POINT
@@ -2637,11 +2944,11 @@ int main(int argc, char **argv)
2944
2945 ebpf_module_t *em = &ebpf_modules[i];
2946 em->thread = st;
2640 - // We always initialize process, because it is responsible to take care of apps integration
2641 - if (em->enabled || !i) {
2947 + em->thread_id = i;
2948 + if (em->enabled) {
2949 st->thread = mallocz(sizeof(netdata_thread_t));
2643 - em->thread_id = i;
2950 em->enabled = NETDATA_THREAD_EBPF_RUNNING;
2951 + em->lifetime = EBPF_NON_FUNCTION_LIFE_TIME;
2952 netdata_thread_create(st->thread, st->name, NETDATA_THREAD_OPTION_DEFAULT, st->start_routine, em);
2953 } else {
2954 em->enabled = NETDATA_THREAD_EBPF_NOT_RUNNING;
@@ -2655,23 +2962,30 @@ int main(int argc, char **argv)
2962 int update_apps_list = update_apps_every - 1;
2963 int process_maps_per_core = ebpf_modules[EBPF_MODULE_PROCESS_IDX].maps_per_core;
2964 //Plugin will be killed when it receives a signal
2658 - while (!ebpf_exit_plugin) {
2965 + for ( ; !ebpf_exit_plugin ; global_iterations_counter++) {
2966 (void)heartbeat_next(&hb, step);
2967
2968 + if (global_iterations_counter % EBPF_DEFAULT_UPDATE_EVERY == 0) {
2969 + pthread_mutex_lock(&lock);
2970 + ebpf_create_statistic_charts(EBPF_DEFAULT_UPDATE_EVERY);
2971 +
2972 + ebpf_send_statistic_data();
2973 + pthread_mutex_unlock(&lock);
2974 + fflush(stdout);
2975 + }
2976 +
2977 pthread_mutex_lock(&ebpf_exit_cleanup);
2662 - if (process_pid_fd != -1) {
2663 - pthread_mutex_lock(&collect_data_mutex);
2664 - if (++update_apps_list == update_apps_every) {
2665 - update_apps_list = 0;
2666 - cleanup_exited_pids();
2667 - collect_data_for_all_processes(process_pid_fd, process_maps_per_core);
2668 -
2669 - pthread_mutex_lock(&lock);
2670 - ebpf_create_apps_charts(apps_groups_root_target);
2671 - pthread_mutex_unlock(&lock);
2672 - }
2673 - pthread_mutex_unlock(&collect_data_mutex);
2978 + pthread_mutex_lock(&collect_data_mutex);
2979 + if (++update_apps_list == update_apps_every) {
2980 + update_apps_list = 0;
2981 + cleanup_exited_pids();
2982 + collect_data_for_all_processes(process_pid_fd, process_maps_per_core);
2983 +
2984 + pthread_mutex_lock(&lock);
2985 + ebpf_create_apps_charts(apps_groups_root_target);
2986 + pthread_mutex_unlock(&lock);
2987 }
2988 + pthread_mutex_unlock(&collect_data_mutex);
2989 pthread_mutex_unlock(&ebpf_exit_cleanup);
2990 }
2991
@@ -2679,4 +2993,3 @@ int main(int argc, char **argv)
2993
2994 return 0;
2995 }
2682 -
collectors/ebpf.plugin/ebpf.d.conf
+3
@@ -19,6 +19,8 @@
19 #
20 # The `maps per core` defines if hash tables will be per core or not. This option is ignored on kernels older than 4.15.
21 #
22 +# The `lifetime` defines the time length a thread will run when it is enabled by a function.
23 +#
24 [global]
25 ebpf load mode = entry
26 apps = no
@@ -27,6 +29,7 @@
29 pid table size = 32768
30 btf path = /sys/kernel/btf/
31 maps per core = yes
32 + lifetime = 300
33
34 #
35 # eBPF Programs
collectors/ebpf.plugin/ebpf.d/cachestat.conf
+3
@@ -26,6 +26,8 @@
26 #
27 # The `maps per core` defines if hash tables will be per core or not. This option is ignored on kernels older than 4.6.
28 #
29 +# The `lifetime` defines the time length a thread will run when it is enabled by a function.
30 +#
31 # Uncomment lines to define specific options for thread.
32 [global]
33 # ebpf load mode = entry
@@ -37,3 +39,4 @@
39 ebpf co-re tracing = trampoline
40 collect pid = real parent
41 # maps per core = yes
42 + lifetime = 300
collectors/ebpf.plugin/ebpf.d/dcstat.conf
+3
@@ -24,6 +24,8 @@
24 #
25 # The `maps per core` defines if hash tables will be per core or not. This option is ignored on kernels older than 4.6.
26 #
27 +# The `lifetime` defines the time length a thread will run when it is enabled by a function.
28 +#
29 # Uncomment lines to define specific options for thread.
30 [global]
31 # ebpf load mode = entry
@@ -35,3 +37,4 @@
37 ebpf co-re tracing = trampoline
38 collect pid = real parent
39 # maps per core = yes
40 + lifetime = 300
collectors/ebpf.plugin/ebpf.d/disk.conf
+4 -1
@@ -3,7 +3,10 @@
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 -#[global]
6 +# The `lifetime` defines the time length a thread will run when it is enabled by a function.
7 +#
8 +[global]
9 # ebpf load mode = entry
10 # update every = 10
11 + lifetime = 300
12
collectors/ebpf.plugin/ebpf.d/fd.conf
+3
@@ -12,6 +12,8 @@
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 # Uncomment lines to define specific options for thread.
18 [global]
19 # ebpf load mode = entry
@@ -22,3 +24,4 @@
24 ebpf type format = auto
25 ebpf co-re tracing = trampoline
26 # maps per core = yes
27 + lifetime = 300
collectors/ebpf.plugin/ebpf.d/filesystem.conf
+4 -1
@@ -3,13 +3,16 @@
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 `lifetime` defines the time length a thread will run when it is enabled by a function.
7 +#
8 # The eBPF collector also creates charts for each running application through an integration with the `apps plugin`.
9 # If you want to disable the integration with `apps.plugin` along with the above charts, change the setting `apps` to
10 # 'no'.
11 #
10 -#[global]
12 +[global]
13 # ebpf load mode = entry
14 # update every = 10
15 + lifetime = 300
16
17 # All filesystems are named as 'NAMEdist' where NAME is the filesystem name while 'dist' is a reference for distribution.
18 [filesystem]
collectors/ebpf.plugin/ebpf.d/functions.conf new
+3
@@ -0,0 +1,3 @@
1 +#[global]
2 +# update every = 5
3 +
collectors/ebpf.plugin/ebpf.d/hardirq.conf
+4 -1
@@ -3,6 +3,9 @@
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 -#[global]
6 +# The `lifetime` defines the time length a thread will run when it is enabled by a function.
7 +#
8 +[global]
9 # ebpf load mode = entry
10 # update every = 10
11 + lifetime = 300
collectors/ebpf.plugin/ebpf.d/mdflush.conf
+5 -1
@@ -2,6 +2,10 @@
2 # `entry` : The eBPF collector only monitors calls for the functions, and does not show charts related to errors.
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 -#[global]
5 +#
6 +# The `lifetime` defines the time length a thread will run when it is enabled by a function.
7 +#
8 +[global]
9 # ebpf load mode = entry
10 # update every = 1
11 + lifetime = 300
collectors/ebpf.plugin/ebpf.d/mount.conf
+4
@@ -12,8 +12,12 @@
12 # `trampoline`: This is the default mode used by the eBPF collector, due the small overhead added to host.
13 # `tracepoint`: When available, the eBPF collector will use kernel tracepoint to monitor syscall.
14 # `probe` : This is the same as legacy code.
15 +#
16 +# The `lifetime` defines the time length a thread will run when it is enabled by a function.
17 +#
18 [global]
19 # ebpf load mode = entry
20 # update every = 1
21 ebpf type format = auto
22 ebpf co-re tracing = trampoline
23 + lifetime = 300
collectors/ebpf.plugin/ebpf.d/network.conf
+3
@@ -26,6 +26,8 @@
26 #
27 # The `maps per core` defines if hash tables will be per core or not. This option is ignored on kernels older than 4.6.
28 #
29 +# The `lifetime` defines the time length a thread will run when it is enabled by a function.
30 +#
31 # Uncomment lines to define specific options for thread.
32 [global]
33 # ebpf load mode = entry
@@ -39,6 +41,7 @@
41 ebpf type format = auto
42 ebpf co-re tracing = trampoline
43 maps per core = no
44 + lifetime = 300
45
46 #
47 # Network Connection
collectors/ebpf.plugin/ebpf.d/oomkill.conf
+5 -1
@@ -2,6 +2,10 @@
2 # `entry` : The eBPF collector only monitors calls for the functions, and does not show charts related to errors.
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 -#[global]
5 +#
6 +# The `lifetime` defines the time length a thread will run when it is enabled by a function.
7 +#
8 +[global]
9 # ebpf load mode = entry
10 # update every = 1
11 + lifetime = 300
collectors/ebpf.plugin/ebpf.d/process.conf
+3
@@ -17,6 +17,8 @@
17 #
18 # The `maps per core` defines if hash tables will be per core or not. This option is ignored on kernels older than 4.6.
19 #
20 +# The `lifetime` defines the time length a thread will run when it is enabled by a function.
21 +#
22 # Uncomment lines to define specific options for thread.
23 [global]
24 # ebpf load mode = entry
@@ -26,3 +28,4 @@
28 # pid table size = 32768
29 collect pid = real parent
30 # maps per core = yes
31 + lifetime = 300
collectors/ebpf.plugin/ebpf.d/shm.conf
+3
@@ -20,6 +20,8 @@
20 #
21 # The `maps per core` defines if hash tables will be per core or not. This option is ignored on kernels older than 4.6.
22 #
23 +# The `lifetime` defines the time length a thread will run when it is enabled by a function.
24 +#
25 # Uncomment lines to define specific options for thread.
26 [global]
27 # ebpf load mode = entry
@@ -30,6 +32,7 @@
32 ebpf type format = auto
33 ebpf co-re tracing = trampoline
34 # maps per core = yes
35 + lifetime = 300
36
37 # List of monitored syscalls
38 [syscalls]
collectors/ebpf.plugin/ebpf.d/softirq.conf
+4 -1
@@ -3,6 +3,9 @@
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 -#[global]
6 +# The `lifetime` defines the time length a thread will run when it is enabled by a function.
7 +#
8 +[global]
9 # ebpf load mode = entry
10 # update every = 10
11 + lifetime = 300
collectors/ebpf.plugin/ebpf.d/swap.conf
+3
@@ -19,6 +19,8 @@
19 #
20 # The `maps per core` defines if hash tables will be per core or not. This option is ignored on kernels older than 4.6.
21 #
22 +# The `lifetime` defines the time length a thread will run when it is enabled by a function.
23 +#
24 # Uncomment lines to define specific options for thread.
25 [global]
26 # ebpf load mode = entry
@@ -29,3 +31,4 @@
31 ebpf type format = auto
32 ebpf co-re tracing = trampoline
33 # maps per core = yes
34 + lifetime = 300
collectors/ebpf.plugin/ebpf.d/sync.conf
+3
@@ -19,6 +19,8 @@
19 # `probe` : This is the same as legacy code.
20 #
21 # The `maps per core` defines if hash tables will be per core or not. This option is ignored on kernels older than 4.6.
22 +#
23 +# The `lifetime` defines the time length a thread will run when it is enabled by a function.
24 #
25 # Uncomment lines to define specific options for thread.
26 [global]
@@ -29,6 +31,7 @@
31 ebpf type format = auto
32 ebpf co-re tracing = trampoline
33 # maps per core = yes
34 + lifetime = 300
35
36 # List of monitored syscalls
37 [syscalls]
collectors/ebpf.plugin/ebpf.d/vfs.conf
+3
@@ -20,6 +20,8 @@
20 #
21 # The `maps per core` defines if hash tables will be per core or not. This option is ignored on kernels older than 4.6.
22 #
23 +# The `lifetime` defines the time length a thread will run when it is enabled by a function.
24 +#
25 # Uncomment lines to define specific options for thread.
26 [global]
27 # ebpf load mode = entry
@@ -30,3 +32,4 @@
32 ebpf type format = auto
33 ebpf co-re tracing = trampoline
34 # maps per core = yes
35 + lifetime = 300
collectors/ebpf.plugin/ebpf.h
+2
@@ -118,6 +118,7 @@ enum ebpf_main_index {
118 EBPF_MODULE_OOMKILL_IDX,
119 EBPF_MODULE_SHM_IDX,
120 EBPF_MODULE_MDFLUSH_IDX,
121 + EBPF_MODULE_FUNCTION_IDX,
122 /* THREADS MUST BE INCLUDED BEFORE THIS COMMENT */
123 EBPF_OPTION_ALL_CHARTS,
124 EBPF_OPTION_VERSION,
@@ -163,6 +164,7 @@ typedef struct ebpf_tracepoint {
164
165 // Statistics charts
166 #define NETDATA_EBPF_THREADS "ebpf_threads"
167 +#define NETDATA_EBPF_LIFE_TIME "ebpf_life_time"
168 #define NETDATA_EBPF_LOAD_METHOD "ebpf_load_methods"
169 #define NETDATA_EBPF_KERNEL_MEMORY "ebpf_kernel_memory"
170 #define NETDATA_EBPF_HASH_TABLES_LOADED "ebpf_hash_tables_count"
collectors/ebpf.plugin/ebpf_apps.c
+30 -24
@@ -1338,8 +1338,10 @@ void cleanup_exited_pids()
1338 p = p->next;
1339
1340 // Clean process structure
1341 - ebpf_process_stat_release(global_process_stats[r]);
1342 - global_process_stats[r] = NULL;
1341 + if (global_process_stats) {
1342 + ebpf_process_stat_release(global_process_stats[r]);
1343 + global_process_stats[r] = NULL;
1344 + }
1345
1346 cleanup_variables_from_other_threads(r);
1347
@@ -1471,36 +1473,40 @@ void collect_data_for_all_processes(int tbl_pid_stats_fd, int maps_per_core)
1473 uint32_t key;
1474 pids = ebpf_root_of_pids; // global list of all processes running
1475 // while (bpf_map_get_next_key(tbl_pid_stats_fd, &key, &next_key) == 0) {
1474 - size_t length = sizeof(ebpf_process_stat_t);
1475 - if (maps_per_core)
1476 - length *= ebpf_nprocs;
1476
1478 - while (pids) {
1479 - key = pids->pid;
1480 - ebpf_process_stat_t *w = global_process_stats[key];
1481 - if (!w) {
1482 - w = ebpf_process_stat_get();
1483 - global_process_stats[key] = w;
1484 - }
1477 + if (tbl_pid_stats_fd != -1) {
1478 + size_t length = sizeof(ebpf_process_stat_t);
1479 + if (maps_per_core)
1480 + length *= ebpf_nprocs;
1481
1486 - if (bpf_map_lookup_elem(tbl_pid_stats_fd, &key, process_stat_vector)) {
1487 - // Clean Process structures
1488 - ebpf_process_stat_release(w);
1489 - global_process_stats[key] = NULL;
1482 + while (pids) {
1483 + key = pids->pid;
1484
1491 - cleanup_variables_from_other_threads(key);
1485 + ebpf_process_stat_t *w = global_process_stats[key];
1486 + if (!w) {
1487 + w = ebpf_process_stat_get();
1488 + global_process_stats[key] = w;
1489 + }
1490
1493 - pids = pids->next;
1494 - continue;
1495 - }
1491 + if (bpf_map_lookup_elem(tbl_pid_stats_fd, &key, process_stat_vector)) {
1492 + // Clean Process structures
1493 + ebpf_process_stat_release(w);
1494 + global_process_stats[key] = NULL;
1495
1497 - ebpf_process_apps_accumulator(process_stat_vector, maps_per_core);
1496 + cleanup_variables_from_other_threads(key);
1497
1499 - memcpy(w, process_stat_vector, sizeof(ebpf_process_stat_t));
1498 + pids = pids->next;
1499 + continue;
1500 + }
1501
1501 - memset(process_stat_vector, 0, length);
1502 + ebpf_process_apps_accumulator(process_stat_vector, maps_per_core);
1503
1503 - pids = pids->next;
1504 + memcpy(w, process_stat_vector, sizeof(ebpf_process_stat_t));
1505 +
1506 + memset(process_stat_vector, 0, length);
1507 +
1508 + pids = pids->next;
1509 + }
1510 }
1511
1512 link_all_processes_to_their_parents();
collectors/ebpf.plugin/ebpf_apps.h
+1
@@ -21,6 +21,7 @@
21 #include "ebpf_disk.h"
22 #include "ebpf_fd.h"
23 #include "ebpf_filesystem.h"
24 +#include "ebpf_functions.h"
25 #include "ebpf_hardirq.h"
26 #include "ebpf_cachestat.h"
27 #include "ebpf_mdflush.h"
collectors/ebpf.plugin/ebpf_cachestat.c
+222 -4
@@ -58,6 +58,10 @@ netdata_ebpf_targets_t cachestat_targets[] = { {.name = "add_to_page_cache_lru",
58 static char *account_page[NETDATA_CACHESTAT_ACCOUNT_DIRTY_END] ={ "account_page_dirtied",
59 "__set_page_dirty", "__folio_mark_dirty" };
60
61 +#ifdef NETDATA_DEV_MODE
62 +int cachestat_disable_priority;
63 +#endif
64 +
65 #ifdef LIBBPF_MAJOR_VERSION
66 /**
67 * Disable probe
@@ -336,6 +340,179 @@ static inline int ebpf_cachestat_load_and_attach(struct cachestat_bpf *obj, ebpf
340 *
341 *****************************************************************/
342
343 +static void ebpf_obsolete_specific_cachestat_charts(char *type, int update_every);
344 +
345 +/**
346 + * Obsolete services
347 + *
348 + * Obsolete all service charts created
349 + *
350 + * @param em a pointer to `struct ebpf_module`
351 + */
352 +static void ebpf_obsolete_services(ebpf_module_t *em)
353 +{
354 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
355 + NETDATA_CACHESTAT_HIT_RATIO_CHART,
356 + "Hit ratio",
357 + EBPF_COMMON_DIMENSION_PERCENTAGE,
358 + NETDATA_CACHESTAT_SUBMENU,
359 + NETDATA_EBPF_CHART_TYPE_LINE,
360 + NETDATA_SYSTEMD_CACHESTAT_HIT_RATIO_CONTEXT,
361 + 21100,
362 + em->update_every);
363 +
364 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
365 + NETDATA_CACHESTAT_DIRTY_CHART,
366 + "Number of dirty pages",
367 + EBPF_CACHESTAT_DIMENSION_PAGE,
368 + NETDATA_CACHESTAT_SUBMENU,
369 + NETDATA_EBPF_CHART_TYPE_LINE,
370 + NETDATA_SYSTEMD_CACHESTAT_MODIFIED_CACHE_CONTEXT,
371 + 21101,
372 + em->update_every);
373 +
374 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
375 + NETDATA_CACHESTAT_HIT_CHART,
376 + "Number of accessed files",
377 + EBPF_CACHESTAT_DIMENSION_HITS,
378 + NETDATA_CACHESTAT_SUBMENU,
379 + NETDATA_EBPF_CHART_TYPE_LINE,
380 + NETDATA_SYSTEMD_CACHESTAT_HIT_FILE_CONTEXT,
381 + 21102,
382 + em->update_every);
383 +
384 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
385 + NETDATA_CACHESTAT_MISSES_CHART,
386 + "Files out of page cache",
387 + EBPF_CACHESTAT_DIMENSION_MISSES,
388 + NETDATA_CACHESTAT_SUBMENU,
389 + NETDATA_EBPF_CHART_TYPE_LINE,
390 + NETDATA_SYSTEMD_CACHESTAT_MISS_FILES_CONTEXT,
391 + 21103,
392 + em->update_every);
393 +}
394 +
395 +/**
396 + * Obsolete cgroup chart
397 + *
398 + * Send obsolete for all charts created before to close.
399 + *
400 + * @param em a pointer to `struct ebpf_module`
401 + */
402 +static inline void ebpf_obsolete_cachestat_cgroup_charts(ebpf_module_t *em) {
403 + pthread_mutex_lock(&mutex_cgroup_shm);
404 +
405 + ebpf_obsolete_services(em);
406 +
407 + ebpf_cgroup_target_t *ect;
408 + for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
409 + if (ect->systemd)
410 + continue;
411 +
412 + ebpf_obsolete_specific_cachestat_charts(ect->name, em->update_every);
413 + }
414 + pthread_mutex_unlock(&mutex_cgroup_shm);
415 +}
416 +
417 +/**
418 + * Obsolete global
419 + *
420 + * Obsolete global charts created by thread.
421 + *
422 + * @param em a pointer to `struct ebpf_module`
423 + */
424 +static void ebpf_obsolete_cachestat_global(ebpf_module_t *em)
425 +{
426 + ebpf_write_chart_obsolete(NETDATA_EBPF_MEMORY_GROUP,
427 + NETDATA_CACHESTAT_HIT_RATIO_CHART,
428 + "Hit ratio",
429 + EBPF_COMMON_DIMENSION_PERCENTAGE,
430 + NETDATA_CACHESTAT_SUBMENU,
431 + NETDATA_EBPF_CHART_TYPE_LINE,
432 + NULL,
433 + 21100,
434 + em->update_every);
435 +
436 + ebpf_write_chart_obsolete(NETDATA_EBPF_MEMORY_GROUP,
437 + NETDATA_CACHESTAT_DIRTY_CHART,
438 + "Number of dirty pages",
439 + EBPF_CACHESTAT_DIMENSION_PAGE,
440 + NETDATA_CACHESTAT_SUBMENU,
441 + NETDATA_EBPF_CHART_TYPE_LINE,
442 + NULL,
443 + 21101,
444 + em->update_every);
445 +
446 + ebpf_write_chart_obsolete(NETDATA_EBPF_MEMORY_GROUP,
447 + NETDATA_CACHESTAT_HIT_CHART,
448 + "Number of accessed files",
449 + EBPF_CACHESTAT_DIMENSION_HITS,
450 + NETDATA_CACHESTAT_SUBMENU,
451 + NETDATA_EBPF_CHART_TYPE_LINE,
452 + NULL,
453 + 21102,
454 + em->update_every);
455 +
456 + ebpf_write_chart_obsolete(NETDATA_EBPF_MEMORY_GROUP,
457 + NETDATA_CACHESTAT_MISSES_CHART,
458 + "Files out of page cache",
459 + EBPF_CACHESTAT_DIMENSION_MISSES,
460 + NETDATA_CACHESTAT_SUBMENU,
461 + NETDATA_EBPF_CHART_TYPE_LINE,
462 + NULL,
463 + 21103,
464 + em->update_every);
465 +}
466 +
467 +/**
468 + * Obsolette apps charts
469 + *
470 + * Obsolete apps charts.
471 + *
472 + * @param em a pointer to the structure with the default values.
473 + */
474 +void ebpf_obsolete_cachestat_apps_charts(struct ebpf_module *em)
475 +{
476 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
477 + NETDATA_CACHESTAT_HIT_RATIO_CHART,
478 + "Hit ratio",
479 + EBPF_COMMON_DIMENSION_PERCENTAGE,
480 + NETDATA_CACHESTAT_SUBMENU,
481 + NETDATA_EBPF_CHART_TYPE_LINE,
482 + NULL,
483 + 20090,
484 + em->update_every);
485 +
486 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
487 + NETDATA_CACHESTAT_DIRTY_CHART,
488 + "Number of dirty pages",
489 + EBPF_CACHESTAT_DIMENSION_PAGE,
490 + NETDATA_CACHESTAT_SUBMENU,
491 + NETDATA_EBPF_CHART_TYPE_STACKED,
492 + NULL,
493 + 20091,
494 + em->update_every);
495 +
496 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY, NETDATA_CACHESTAT_HIT_CHART,
497 + "Number of accessed files",
498 + EBPF_CACHESTAT_DIMENSION_HITS,
499 + NETDATA_CACHESTAT_SUBMENU,
500 + NETDATA_EBPF_CHART_TYPE_STACKED,
501 + NULL,
502 + 20092,
503 + em->update_every);
504 +
505 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
506 + NETDATA_CACHESTAT_MISSES_CHART,
507 + "Files out of page cache",
508 + EBPF_CACHESTAT_DIMENSION_MISSES,
509 + NETDATA_CACHESTAT_SUBMENU,
510 + NETDATA_EBPF_CHART_TYPE_STACKED,
511 + NULL,
512 + 20093,
513 + em->update_every);
514 +}
515 +
516 /**
517 * Cachestat exit.
518 *
@@ -347,17 +524,47 @@ static void ebpf_cachestat_exit(void *ptr)
524 {
525 ebpf_module_t *em = (ebpf_module_t *)ptr;
526
527 + if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
528 + pthread_mutex_lock(&lock);
529 + if (em->cgroup_charts) {
530 + ebpf_obsolete_cachestat_cgroup_charts(em);
531 + fflush(stdout);
532 + }
533 +
534 + if (em->apps_charts & NETDATA_EBPF_APPS_FLAG_CHART_CREATED) {
535 + ebpf_obsolete_cachestat_apps_charts(em);
536 + }
537 +
538 + ebpf_obsolete_cachestat_global(em);
539 +
540 +#ifdef NETDATA_DEV_MODE
541 + if (ebpf_aral_cachestat_pid)
542 + ebpf_statistic_obsolete_aral_chart(em, cachestat_disable_priority);
543 +#endif
544 +
545 +
546 + fflush(stdout);
547 + pthread_mutex_unlock(&lock);
548 + }
549 +
550 + ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_REMOVE);
551 +
552 #ifdef LIBBPF_MAJOR_VERSION
351 - if (cachestat_bpf_obj)
553 + if (cachestat_bpf_obj) {
554 cachestat_bpf__destroy(cachestat_bpf_obj);
555 + cachestat_bpf_obj = NULL;
556 + }
557 #endif
558
559 if (em->objects) {
560 ebpf_unload_legacy_code(em->objects, em->probe_links);
561 + em->objects = NULL;
562 + em->probe_links = NULL;
563 }
564
565 pthread_mutex_lock(&ebpf_exit_cleanup);
566 em->enabled = NETDATA_THREAD_EBPF_STOPPED;
567 + ebpf_update_stats(&plugin_statistics, em);
568 pthread_mutex_unlock(&ebpf_exit_cleanup);
569 }
570
@@ -1079,7 +1286,9 @@ static void cachestat_collector(ebpf_module_t *em)
1286 heartbeat_init(&hb);
1287 int counter = update_every - 1;
1288 //This will be cancelled by its parent
1082 - while (!ebpf_exit_plugin) {
1289 + uint32_t running_time = 0;
1290 + uint32_t lifetime = em->lifetime;
1291 + while (!ebpf_exit_plugin && running_time < lifetime) {
1292 (void)heartbeat_next(&hb, USEC_PER_SEC);
1293
1294 if (ebpf_exit_plugin || ++counter != update_every)
@@ -1112,6 +1321,15 @@ static void cachestat_collector(ebpf_module_t *em)
1321
1322 pthread_mutex_unlock(&lock);
1323 pthread_mutex_unlock(&collect_data_mutex);
1324 +
1325 + pthread_mutex_lock(&ebpf_exit_cleanup);
1326 + if (running_time && !em->running_time)
1327 + running_time = update_every;
1328 + else
1329 + running_time += update_every;
1330 +
1331 + em->running_time = running_time;
1332 + pthread_mutex_unlock(&ebpf_exit_cleanup);
1333 }
1334 }
1335
@@ -1307,11 +1525,11 @@ void *ebpf_cachestat_thread(void *ptr)
1525
1526 pthread_mutex_lock(&lock);
1527 ebpf_update_stats(&plugin_statistics, em);
1310 - ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps);
1528 + ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_ADD);
1529 ebpf_create_memory_charts(em);
1530 #ifdef NETDATA_DEV_MODE
1531 if (ebpf_aral_cachestat_pid)
1314 - ebpf_statistic_create_aral_chart(NETDATA_EBPF_CACHESTAT_ARAL_NAME, em);
1532 + cachestat_disable_priority = ebpf_statistic_create_aral_chart(NETDATA_EBPF_CACHESTAT_ARAL_NAME, em);
1533 #endif
1534
1535 pthread_mutex_unlock(&lock);
collectors/ebpf.plugin/ebpf_cachestat.h
+2 -1
@@ -3,8 +3,9 @@
3 #ifndef NETDATA_EBPF_CACHESTAT_H
4 #define NETDATA_EBPF_CACHESTAT_H 1
5
6 -// Module name
6 +// Module name & description
7 #define NETDATA_EBPF_MODULE_NAME_CACHESTAT "cachestat"
8 +#define NETDATA_EBPF_CACHESTAT_MODULE_DESC "Monitor Linux page cache internal functions. This thread is integrated with apps and cgroup."
9
10 // charts
11 #define NETDATA_CACHESTAT_HIT_RATIO_CHART "cachestat_ratio"
collectors/ebpf.plugin/ebpf_dcstat.c
+206 -7
@@ -59,6 +59,10 @@ netdata_ebpf_targets_t dc_targets[] = { {.name = "lookup_fast", .mode = EBPF_LOA
59 {.name = "d_lookup", .mode = EBPF_LOAD_TRAMPOLINE},
60 {.name = NULL, .mode = EBPF_LOAD_TRAMPOLINE}};
61
62 +#ifdef NETDATA_DEV_MODE
63 +int dcstat_disable_priority;
64 +#endif
65 +
66 #ifdef LIBBPF_MAJOR_VERSION
67 /**
68 * Disable probe
@@ -285,6 +289,160 @@ void dcstat_update_publish(netdata_publish_dcstat_t *out, uint64_t cache_access,
289 *
290 *****************************************************************/
291
292 +static void ebpf_obsolete_specific_dc_charts(char *type, int update_every);
293 +
294 +/**
295 + * Obsolete services
296 + *
297 + * Obsolete all service charts created
298 + *
299 + * @param em a pointer to `struct ebpf_module`
300 + */
301 +static void ebpf_obsolete_dc_services(ebpf_module_t *em)
302 +{
303 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
304 + NETDATA_DC_HIT_CHART,
305 + "Percentage of files inside directory cache",
306 + EBPF_COMMON_DIMENSION_PERCENTAGE,
307 + NETDATA_DIRECTORY_CACHE_SUBMENU,
308 + NETDATA_EBPF_CHART_TYPE_LINE,
309 + NETDATA_SYSTEMD_DC_HIT_RATIO_CONTEXT,
310 + 21200,
311 + em->update_every);
312 +
313 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
314 + NETDATA_DC_REFERENCE_CHART,
315 + "Count file access",
316 + EBPF_COMMON_DIMENSION_FILES,
317 + NETDATA_DIRECTORY_CACHE_SUBMENU,
318 + NETDATA_EBPF_CHART_TYPE_LINE,
319 + NETDATA_SYSTEMD_DC_REFERENCE_CONTEXT,
320 + 21201,
321 + em->update_every);
322 +
323 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
324 + NETDATA_DC_REQUEST_NOT_CACHE_CHART,
325 + "Files not present inside directory cache",
326 + EBPF_COMMON_DIMENSION_FILES,
327 + NETDATA_DIRECTORY_CACHE_SUBMENU,
328 + NETDATA_EBPF_CHART_TYPE_LINE,
329 + NETDATA_SYSTEMD_DC_NOT_CACHE_CONTEXT,
330 + 21202,
331 + em->update_every);
332 +
333 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
334 + NETDATA_DC_REQUEST_NOT_FOUND_CHART,
335 + "Files not found",
336 + EBPF_COMMON_DIMENSION_FILES,
337 + NETDATA_DIRECTORY_CACHE_SUBMENU,
338 + NETDATA_EBPF_CHART_TYPE_LINE,
339 + NETDATA_SYSTEMD_DC_NOT_FOUND_CONTEXT,
340 + 21202,
341 + em->update_every);
342 +}
343 +
344 +/**
345 + * Obsolete cgroup chart
346 + *
347 + * Send obsolete for all charts created before to close.
348 + *
349 + * @param em a pointer to `struct ebpf_module`
350 + */
351 +static inline void ebpf_obsolete_dc_cgroup_charts(ebpf_module_t *em) {
352 + pthread_mutex_lock(&mutex_cgroup_shm);
353 +
354 + ebpf_obsolete_dc_services(em);
355 +
356 + ebpf_cgroup_target_t *ect;
357 + for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
358 + if (ect->systemd)
359 + continue;
360 +
361 + ebpf_obsolete_specific_dc_charts(ect->name, em->update_every);
362 + }
363 + pthread_mutex_unlock(&mutex_cgroup_shm);
364 +}
365 +
366 +/**
367 + * Obsolette apps charts
368 + *
369 + * Obsolete apps charts.
370 + *
371 + * @param em a pointer to the structure with the default values.
372 + */
373 +void ebpf_obsolete_dc_apps_charts(struct ebpf_module *em)
374 +{
375 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
376 + NETDATA_DC_HIT_CHART,
377 + "Percentage of files inside directory cache",
378 + EBPF_COMMON_DIMENSION_PERCENTAGE,
379 + NETDATA_DIRECTORY_CACHE_SUBMENU,
380 + NETDATA_EBPF_CHART_TYPE_LINE,
381 + NULL,
382 + 20100,
383 + em->update_every);
384 +
385 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
386 + NETDATA_DC_REFERENCE_CHART,
387 + "Count file access",
388 + EBPF_COMMON_DIMENSION_FILES,
389 + NETDATA_DIRECTORY_CACHE_SUBMENU,
390 + NETDATA_EBPF_CHART_TYPE_STACKED,
391 + NULL,
392 + 20101,
393 + em->update_every);
394 +
395 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
396 + NETDATA_DC_REQUEST_NOT_CACHE_CHART,
397 + "Files not present inside directory cache",
398 + EBPF_COMMON_DIMENSION_FILES,
399 + NETDATA_DIRECTORY_CACHE_SUBMENU,
400 + NETDATA_EBPF_CHART_TYPE_STACKED,
401 + NULL,
402 + 20102,
403 + em->update_every);
404 +
405 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
406 + NETDATA_DC_REQUEST_NOT_FOUND_CHART,
407 + "Files not found",
408 + EBPF_COMMON_DIMENSION_FILES,
409 + NETDATA_DIRECTORY_CACHE_SUBMENU,
410 + NETDATA_EBPF_CHART_TYPE_STACKED,
411 + NULL,
412 + 20103,
413 + em->update_every);
414 +}
415 +
416 +/**
417 + * Obsolete global
418 + *
419 + * Obsolete global charts created by thread.
420 + *
421 + * @param em a pointer to `struct ebpf_module`
422 + */
423 +static void ebpf_obsolete_dc_global(ebpf_module_t *em)
424 +{
425 + ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY,
426 + NETDATA_DC_HIT_CHART,
427 + "Percentage of files inside directory cache",
428 + EBPF_COMMON_DIMENSION_PERCENTAGE,
429 + NETDATA_DIRECTORY_CACHE_SUBMENU,
430 + NETDATA_EBPF_CHART_TYPE_LINE,
431 + NULL,
432 + 21200,
433 + em->update_every);
434 +
435 + ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY,
436 + NETDATA_DC_REFERENCE_CHART,
437 + "Variables used to calculate hit ratio.",
438 + EBPF_COMMON_DIMENSION_FILES,
439 + NETDATA_DIRECTORY_CACHE_SUBMENU,
440 + NETDATA_EBPF_CHART_TYPE_LINE,
441 + NULL,
442 + 21201,
443 + em->update_every);
444 +}
445 +
446 /**
447 * DCstat exit
448 *
@@ -296,16 +454,46 @@ static void ebpf_dcstat_exit(void *ptr)
454 {
455 ebpf_module_t *em = (ebpf_module_t *)ptr;
456
457 + if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
458 + pthread_mutex_lock(&lock);
459 + if (em->cgroup_charts) {
460 + ebpf_obsolete_dc_cgroup_charts(em);
461 + fflush(stdout);
462 + }
463 +
464 + if (em->apps_charts & NETDATA_EBPF_APPS_FLAG_CHART_CREATED) {
465 + ebpf_obsolete_dc_apps_charts(em);
466 + }
467 +
468 + ebpf_obsolete_dc_global(em);
469 +
470 +#ifdef NETDATA_DEV_MODE
471 + if (ebpf_aral_dcstat_pid)
472 + ebpf_statistic_obsolete_aral_chart(em, dcstat_disable_priority);
473 +#endif
474 +
475 + fflush(stdout);
476 + pthread_mutex_unlock(&lock);
477 + }
478 +
479 + ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_REMOVE);
480 +
481 #ifdef LIBBPF_MAJOR_VERSION
300 - if (dc_bpf_obj)
482 + if (dc_bpf_obj) {
483 dc_bpf__destroy(dc_bpf_obj);
484 + dc_bpf_obj = NULL;
485 + }
486 #endif
487
304 - if (em->objects)
488 + if (em->objects){
489 ebpf_unload_legacy_code(em->objects, em->probe_links);
490 + em->objects = NULL;
491 + em->probe_links = NULL;
492 + }
493
494 pthread_mutex_lock(&ebpf_exit_cleanup);
495 em->enabled = NETDATA_THREAD_EBPF_STOPPED;
496 + ebpf_update_stats(&plugin_statistics, em);
497 pthread_mutex_unlock(&ebpf_exit_cleanup);
498 }
499
@@ -979,7 +1167,9 @@ static void dcstat_collector(ebpf_module_t *em)
1167 heartbeat_init(&hb);
1168 int counter = update_every - 1;
1169 int maps_per_core = em->maps_per_core;
982 - while (!ebpf_exit_plugin) {
1170 + uint32_t running_time = 0;
1171 + uint32_t lifetime = em->lifetime;
1172 + while (!ebpf_exit_plugin && running_time < lifetime) {
1173 (void)heartbeat_next(&hb, USEC_PER_SEC);
1174
1175 if (ebpf_exit_plugin || ++counter != update_every)
@@ -1012,6 +1202,15 @@ static void dcstat_collector(ebpf_module_t *em)
1202
1203 pthread_mutex_unlock(&lock);
1204 pthread_mutex_unlock(&collect_data_mutex);
1205 +
1206 + pthread_mutex_lock(&ebpf_exit_cleanup);
1207 + if (running_time && !em->running_time)
1208 + running_time = update_every;
1209 + else
1210 + running_time += update_every;
1211 +
1212 + em->running_time = running_time;
1213 + pthread_mutex_unlock(&ebpf_exit_cleanup);
1214 }
1215 }
1216
@@ -1028,7 +1227,7 @@ static void dcstat_collector(ebpf_module_t *em)
1227 *
1228 * @param update_every value to overwrite the update frequency set by the server.
1229 */
1031 -static void ebpf_create_filesystem_charts(int update_every)
1230 +static void ebpf_create_dc_global_charts(int update_every)
1231 {
1232 ebpf_create_chart(NETDATA_FILESYSTEM_FAMILY, NETDATA_DC_HIT_CHART,
1233 "Percentage of files inside directory cache",
@@ -1156,12 +1355,12 @@ void *ebpf_dcstat_thread(void *ptr)
1355 algorithms, NETDATA_DCSTAT_IDX_END);
1356
1357 pthread_mutex_lock(&lock);
1159 - ebpf_create_filesystem_charts(em->update_every);
1358 + ebpf_create_dc_global_charts(em->update_every);
1359 ebpf_update_stats(&plugin_statistics, em);
1161 - ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps);
1360 + ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_ADD);
1361 #ifdef NETDATA_DEV_MODE
1362 if (ebpf_aral_dcstat_pid)
1164 - ebpf_statistic_create_aral_chart(NETDATA_EBPF_DCSTAT_ARAL_NAME, em);
1363 + dcstat_disable_priority = ebpf_statistic_create_aral_chart(NETDATA_EBPF_DCSTAT_ARAL_NAME, em);
1364 #endif
1365
1366 pthread_mutex_unlock(&lock);
collectors/ebpf.plugin/ebpf_dcstat.h
+2 -1
@@ -3,8 +3,9 @@
3 #ifndef NETDATA_EBPF_DCSTAT_H
4 #define NETDATA_EBPF_DCSTAT_H 1
5
6 -// Module name
6 +// Module name & description
7 #define NETDATA_EBPF_MODULE_NAME_DCSTAT "dcstat"
8 +#define NETDATA_EBPF_DC_MODULE_DESC "Monitor file access using directory cache. This thread is integrated with apps and cgroup."
9
10 // charts
11 #define NETDATA_DC_HIT_CHART "dc_hit_ratio"
collectors/ebpf.plugin/ebpf_disk.c
+63 -4
@@ -448,6 +448,7 @@ static void ebpf_cleanup_plot_disks()
448
449 move = next;
450 }
451 + plot_disks = NULL;
452 }
453
454 /**
@@ -465,6 +466,36 @@ static void ebpf_cleanup_disk_list()
466
467 move = next;
468 }
469 + disk_list = NULL;
470 +}
471 +
472 +/**
473 + * Obsolete global
474 + *
475 + * Obsolete global charts created by thread.
476 + *
477 + * @param em a pointer to `struct ebpf_module`
478 + */
479 +static void ebpf_obsolete_disk_global(ebpf_module_t *em)
480 +{
481 + ebpf_publish_disk_t *move = plot_disks;
482 + while (move) {
483 + netdata_ebpf_disks_t *ned = move->plot;
484 + uint32_t flags = ned->flags;
485 + if (flags & NETDATA_DISK_CHART_CREATED) {
486 + ebpf_write_chart_obsolete(ned->histogram.name,
487 + ned->family,
488 + "Disk latency",
489 + EBPF_COMMON_DIMENSION_CALL,
490 + ned->family,
491 + NETDATA_EBPF_CHART_TYPE_STACKED,
492 + NULL,
493 + ned->histogram.order,
494 + em->update_every);
495 + }
496 +
497 + move = move->next;
498 + }
499 }
500
501 /**
@@ -478,15 +509,29 @@ static void ebpf_disk_exit(void *ptr)
509 {
510 ebpf_module_t *em = (ebpf_module_t *)ptr;
511
481 - if (em->objects)
482 - ebpf_unload_legacy_code(em->objects, em->probe_links);
512 + if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
513 + pthread_mutex_lock(&lock);
514 +
515 + ebpf_obsolete_disk_global(em);
516
517 + pthread_mutex_unlock(&lock);
518 + fflush(stdout);
519 + }
520 ebpf_disk_disable_tracepoints();
521
522 + ebpf_update_kernel_memory_with_vector(&plugin_statistics, disk_maps, EBPF_ACTION_STAT_REMOVE);
523 +
524 + if (em->objects) {
525 + ebpf_unload_legacy_code(em->objects, em->probe_links);
526 + em->objects = NULL;
527 + em->probe_links = NULL;
528 + }
529 +
530 if (dimensions)
531 ebpf_histogram_dimension_cleanup(dimensions, NETDATA_EBPF_HIST_MAX_BINS);
532
533 freez(disk_hash_values);
534 + disk_hash_values = NULL;
535 pthread_mutex_destroy(&plot_mutex);
536
537 ebpf_cleanup_plot_disks();
@@ -494,6 +539,7 @@ static void ebpf_disk_exit(void *ptr)
539
540 pthread_mutex_lock(&ebpf_exit_cleanup);
541 em->enabled = NETDATA_THREAD_EBPF_STOPPED;
542 + ebpf_update_stats(&plugin_statistics, em);
543 pthread_mutex_unlock(&ebpf_exit_cleanup);
544 }
545
@@ -640,6 +686,8 @@ static void ebpf_create_hd_charts(netdata_ebpf_disks_t *w, int update_every)
686 order++;
687
688 w->flags |= NETDATA_DISK_CHART_CREATED;
689 +
690 + fflush(stdout);
691 }
692
693 /**
@@ -728,7 +776,9 @@ static void disk_collector(ebpf_module_t *em)
776 heartbeat_init(&hb);
777 int counter = update_every - 1;
778 int maps_per_core = em->maps_per_core;
731 - while (!ebpf_exit_plugin) {
779 + uint32_t running_time = 0;
780 + uint32_t lifetime = em->lifetime;
781 + while (!ebpf_exit_plugin && running_time < lifetime) {
782 (void)heartbeat_next(&hb, USEC_PER_SEC);
783
784 if (ebpf_exit_plugin || ++counter != update_every)
@@ -743,6 +793,15 @@ static void disk_collector(ebpf_module_t *em)
793 pthread_mutex_unlock(&lock);
794
795 ebpf_update_disks(em);
796 +
797 + pthread_mutex_lock(&ebpf_exit_cleanup);
798 + if (running_time && !em->running_time)
799 + running_time = update_every;
800 + else
801 + running_time += update_every;
802 +
803 + em->running_time = running_time;
804 + pthread_mutex_unlock(&ebpf_exit_cleanup);
805 }
806 }
807
@@ -866,7 +925,7 @@ void *ebpf_disk_thread(void *ptr)
925
926 pthread_mutex_lock(&lock);
927 ebpf_update_stats(&plugin_statistics, em);
869 - ebpf_update_kernel_memory_with_vector(&plugin_statistics, disk_maps);
928 + ebpf_update_kernel_memory_with_vector(&plugin_statistics, disk_maps, EBPF_ACTION_STAT_ADD);
929 pthread_mutex_unlock(&lock);
930
931 disk_collector(em);
collectors/ebpf.plugin/ebpf_disk.h
+2 -1
@@ -3,8 +3,9 @@
3 #ifndef NETDATA_EBPF_DISK_H
4 #define NETDATA_EBPF_DISK_H 1
5
6 -// Module name
6 +// Module name & description
7 #define NETDATA_EBPF_MODULE_NAME_DISK "disk"
8 +#define NETDATA_EBPF_DISK_MODULE_DESC "Monitor disk latency independent of filesystem."
9
10 #include "libnetdata/avl/avl.h"
11 #include "libnetdata/ebpf/ebpf.h"
collectors/ebpf.plugin/ebpf_fd.c
+217 -5
@@ -57,6 +57,10 @@ netdata_ebpf_targets_t fd_targets[] = { {.name = "open", .mode = EBPF_LOAD_TRAMP
57 {.name = "close", .mode = EBPF_LOAD_TRAMPOLINE},
58 {.name = NULL, .mode = EBPF_LOAD_TRAMPOLINE}};
59
60 +#ifdef NETDATA_DEV_MODE
61 +int fd_disable_priority;
62 +#endif
63 +
64 #ifdef LIBBPF_MAJOR_VERSION
65 /**
66 * Disable probe
@@ -369,6 +373,170 @@ static inline int ebpf_fd_load_and_attach(struct fd_bpf *obj, ebpf_module_t *em)
373 *
374 *****************************************************************/
375
376 +static void ebpf_obsolete_specific_fd_charts(char *type, ebpf_module_t *em);
377 +
378 +/**
379 + * Obsolete services
380 + *
381 + * Obsolete all service charts created
382 + *
383 + * @param em a pointer to `struct ebpf_module`
384 + */
385 +static void ebpf_obsolete_fd_services(ebpf_module_t *em)
386 +{
387 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
388 + NETDATA_SYSCALL_APPS_FILE_OPEN,
389 + "Number of open files",
390 + EBPF_COMMON_DIMENSION_CALL,
391 + NETDATA_APPS_FILE_CGROUP_GROUP,
392 + NETDATA_EBPF_CHART_TYPE_STACKED,
393 + NETDATA_CGROUP_FD_OPEN_CONTEXT,
394 + 20061,
395 + em->update_every);
396 +
397 + if (em->mode < MODE_ENTRY) {
398 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
399 + NETDATA_SYSCALL_APPS_FILE_OPEN_ERROR,
400 + "Fails to open files",
401 + EBPF_COMMON_DIMENSION_CALL,
402 + NETDATA_APPS_FILE_CGROUP_GROUP,
403 + NETDATA_EBPF_CHART_TYPE_STACKED,
404 + NETDATA_CGROUP_FD_OPEN_ERR_CONTEXT,
405 + 20062,
406 + em->update_every);
407 + }
408 +
409 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
410 + NETDATA_SYSCALL_APPS_FILE_CLOSED,
411 + "Files closed",
412 + EBPF_COMMON_DIMENSION_CALL,
413 + NETDATA_APPS_FILE_CGROUP_GROUP,
414 + NETDATA_EBPF_CHART_TYPE_STACKED,
415 + NETDATA_CGROUP_FD_CLOSE_CONTEXT,
416 + 20063,
417 + em->update_every);
418 +
419 + if (em->mode < MODE_ENTRY) {
420 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
421 + NETDATA_SYSCALL_APPS_FILE_CLOSE_ERROR,
422 + "Fails to close files",
423 + EBPF_COMMON_DIMENSION_CALL,
424 + NETDATA_APPS_FILE_CGROUP_GROUP,
425 + NETDATA_EBPF_CHART_TYPE_STACKED,
426 + NETDATA_CGROUP_FD_CLOSE_ERR_CONTEXT,
427 + 20064,
428 + em->update_every);
429 + }
430 +}
431 +
432 +/**
433 + * Obsolete cgroup chart
434 + *
435 + * Send obsolete for all charts created before to close.
436 + *
437 + * @param em a pointer to `struct ebpf_module`
438 + */
439 +static inline void ebpf_obsolete_fd_cgroup_charts(ebpf_module_t *em) {
440 + pthread_mutex_lock(&mutex_cgroup_shm);
441 +
442 + ebpf_obsolete_fd_services(em);
443 +
444 + ebpf_cgroup_target_t *ect;
445 + for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
446 + if (ect->systemd)
447 + continue;
448 +
449 + ebpf_obsolete_specific_fd_charts(ect->name, em);
450 + }
451 + pthread_mutex_unlock(&mutex_cgroup_shm);
452 +}
453 +
454 +/**
455 + * Obsolette apps charts
456 + *
457 + * Obsolete apps charts.
458 + *
459 + * @param em a pointer to the structure with the default values.
460 + */
461 +void ebpf_obsolete_fd_apps_charts(struct ebpf_module *em)
462 +{
463 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
464 + NETDATA_SYSCALL_APPS_FILE_OPEN,
465 + "Number of open files",
466 + EBPF_COMMON_DIMENSION_CALL,
467 + NETDATA_APPS_FILE_GROUP,
468 + NETDATA_EBPF_CHART_TYPE_STACKED,
469 + NULL,
470 + 20061,
471 + em->update_every);
472 +
473 + if (em->mode < MODE_ENTRY) {
474 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
475 + NETDATA_SYSCALL_APPS_FILE_OPEN_ERROR,
476 + "Fails to open files",
477 + EBPF_COMMON_DIMENSION_CALL,
478 + NETDATA_APPS_FILE_GROUP,
479 + NETDATA_EBPF_CHART_TYPE_STACKED,
480 + NULL,
481 + 20062,
482 + em->update_every);
483 + }
484 +
485 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
486 + NETDATA_SYSCALL_APPS_FILE_CLOSED,
487 + "Files closed",
488 + EBPF_COMMON_DIMENSION_CALL,
489 + NETDATA_APPS_FILE_GROUP,
490 + NETDATA_EBPF_CHART_TYPE_STACKED,
491 + NULL,
492 + 20063,
493 + em->update_every);
494 +
495 + if (em->mode < MODE_ENTRY) {
496 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
497 + NETDATA_SYSCALL_APPS_FILE_CLOSE_ERROR,
498 + "Fails to close files",
499 + EBPF_COMMON_DIMENSION_CALL,
500 + NETDATA_APPS_FILE_GROUP,
501 + NETDATA_EBPF_CHART_TYPE_STACKED,
502 + NULL,
503 + 20064,
504 + em->update_every);
505 + }
506 +}
507 +
508 +/**
509 + * Obsolete global
510 + *
511 + * Obsolete global charts created by thread.
512 + *
513 + * @param em a pointer to `struct ebpf_module`
514 + */
515 +static void ebpf_obsolete_fd_global(ebpf_module_t *em)
516 +{
517 + ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY,
518 + NETDATA_FILE_OPEN_CLOSE_COUNT,
519 + "Open and close calls",
520 + EBPF_COMMON_DIMENSION_CALL,
521 + NETDATA_FILE_GROUP,
522 + NETDATA_EBPF_CHART_TYPE_LINE,
523 + NULL,
524 + NETDATA_CHART_PRIO_EBPF_FD_CHARTS,
525 + em->update_every);
526 +
527 + if (em->mode < MODE_ENTRY) {
528 + ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY,
529 + NETDATA_FILE_OPEN_ERR_COUNT,
530 + "Open fails",
531 + EBPF_COMMON_DIMENSION_CALL,
532 + NETDATA_FILE_GROUP,
533 + NETDATA_EBPF_CHART_TYPE_LINE,
534 + NULL,
535 + NETDATA_CHART_PRIO_EBPF_FD_CHARTS + 1,
536 + em->update_every);
537 + }
538 +}
539 +
540 /**
541 * FD Exit
542 *
@@ -380,15 +548,46 @@ static void ebpf_fd_exit(void *ptr)
548 {
549 ebpf_module_t *em = (ebpf_module_t *)ptr;
550
551 + if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
552 + pthread_mutex_lock(&lock);
553 + if (em->cgroup_charts) {
554 + ebpf_obsolete_fd_cgroup_charts(em);
555 + fflush(stdout);
556 + }
557 +
558 + if (em->apps_charts & NETDATA_EBPF_APPS_FLAG_CHART_CREATED) {
559 + ebpf_obsolete_fd_apps_charts(em);
560 + }
561 +
562 + ebpf_obsolete_fd_global(em);
563 +
564 +#ifdef NETDATA_DEV_MODE
565 + if (ebpf_aral_fd_pid)
566 + ebpf_statistic_obsolete_aral_chart(em, fd_disable_priority);
567 +#endif
568 +
569 +
570 + fflush(stdout);
571 + pthread_mutex_unlock(&lock);
572 + }
573 +
574 + ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_REMOVE);
575 +
576 #ifdef LIBBPF_MAJOR_VERSION
384 - if (fd_bpf_obj)
577 + if (fd_bpf_obj) {
578 fd_bpf__destroy(fd_bpf_obj);
579 + fd_bpf_obj = NULL;
580 + }
581 #endif
387 - if (em->objects)
582 + if (em->objects) {
583 ebpf_unload_legacy_code(em->objects, em->probe_links);
584 + em->objects = NULL;
585 + em->probe_links = NULL;
586 + }
587
588 pthread_mutex_lock(&ebpf_exit_cleanup);
589 em->enabled = NETDATA_THREAD_EBPF_STOPPED;
590 + ebpf_update_stats(&plugin_statistics, em);
591 pthread_mutex_unlock(&ebpf_exit_cleanup);
592 }
593
@@ -935,7 +1134,9 @@ static void fd_collector(ebpf_module_t *em)
1134 int update_every = em->update_every;
1135 int counter = update_every - 1;
1136 int maps_per_core = em->maps_per_core;
938 - while (!ebpf_exit_plugin) {
1137 + uint32_t running_time = 0;
1138 + uint32_t lifetime = em->lifetime;
1139 + while (!ebpf_exit_plugin && running_time < lifetime) {
1140 (void)heartbeat_next(&hb, USEC_PER_SEC);
1141
1142 if (ebpf_exit_plugin || ++counter != update_every)
@@ -968,6 +1169,15 @@ static void fd_collector(ebpf_module_t *em)
1169
1170 pthread_mutex_unlock(&lock);
1171 pthread_mutex_unlock(&collect_data_mutex);
1172 +
1173 + pthread_mutex_lock(&ebpf_exit_cleanup);
1174 + if (running_time && !em->running_time)
1175 + running_time = update_every;
1176 + else
1177 + running_time += update_every;
1178 +
1179 + em->running_time = running_time;
1180 + pthread_mutex_unlock(&ebpf_exit_cleanup);
1181 }
1182 }
1183
@@ -1066,6 +1276,8 @@ static void ebpf_create_fd_global_charts(ebpf_module_t *em)
1276 NETDATA_FD_SYSCALL_END,
1277 em->update_every, NETDATA_EBPF_MODULE_NAME_FD);
1278 }
1279 +
1280 + fflush(stdout);
1281 }
1282
1283 /*****************************************************************
@@ -1165,10 +1377,10 @@ void *ebpf_fd_thread(void *ptr)
1377 pthread_mutex_lock(&lock);
1378 ebpf_create_fd_global_charts(em);
1379 ebpf_update_stats(&plugin_statistics, em);
1168 - ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps);
1380 + ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_ADD);
1381 #ifdef NETDATA_DEV_MODE
1382 if (ebpf_aral_fd_pid)
1171 - ebpf_statistic_create_aral_chart(NETDATA_EBPF_FD_ARAL_NAME, em);
1383 + fd_disable_priority = ebpf_statistic_create_aral_chart(NETDATA_EBPF_FD_ARAL_NAME, em);
1384 #endif
1385
1386 pthread_mutex_unlock(&lock);
collectors/ebpf.plugin/ebpf_fd.h
+2 -1
@@ -3,8 +3,9 @@
3 #ifndef NETDATA_EBPF_FD_H
4 #define NETDATA_EBPF_FD_H 1
5
6 -// Module name
6 +// Module name & File description
7 #define NETDATA_EBPF_MODULE_NAME_FD "filedescriptor"
8 +#define NETDATA_EBPF_FD_MODULE_DESC "Monitor when files are open and closed. This thread is integrated with apps and cgroup."
9
10 // Menu group
11 #define NETDATA_FILE_GROUP "file_access"
collectors/ebpf.plugin/ebpf_filesystem.c
+129 -30
@@ -395,13 +395,15 @@ static void ebpf_create_fs_charts(int update_every)
395 snprintfz(chart_name, 63, "%s_read_latency", efp->filesystem);
396 efp->hread.name = strdupz(chart_name);
397 efp->hread.title = strdupz(title);
398 + efp->hread.ctx = NULL;
399 efp->hread.order = order;
400 efp->family_name = strdupz(family);
401
402 ebpf_create_chart(NETDATA_FILESYSTEM_FAMILY, efp->hread.name,
402 - title,
403 - EBPF_COMMON_DIMENSION_CALL, family,
404 - "filesystem.read_latency", NETDATA_EBPF_CHART_TYPE_STACKED, order, ebpf_create_global_dimension,
403 + efp->hread.title,
404 + EBPF_COMMON_DIMENSION_CALL, efp->family_name,
405 + "filesystem.read_latency", NETDATA_EBPF_CHART_TYPE_STACKED, order,
406 + ebpf_create_global_dimension,
407 filesystem_publish_aggregated, NETDATA_EBPF_HIST_MAX_BINS,
408 update_every, NETDATA_EBPF_MODULE_NAME_FILESYSTEM);
409 order++;
@@ -410,11 +412,13 @@ static void ebpf_create_fs_charts(int update_every)
412 snprintfz(chart_name, 63, "%s_write_latency", efp->filesystem);
413 efp->hwrite.name = strdupz(chart_name);
414 efp->hwrite.title = strdupz(title);
415 + efp->hwrite.ctx = NULL;
416 efp->hwrite.order = order;
417 ebpf_create_chart(NETDATA_FILESYSTEM_FAMILY, efp->hwrite.name,
415 - title,
416 - EBPF_COMMON_DIMENSION_CALL, family,
417 - "filesystem.write_latency", NETDATA_EBPF_CHART_TYPE_STACKED, order, ebpf_create_global_dimension,
418 + efp->hwrite.title,
419 + EBPF_COMMON_DIMENSION_CALL, efp->family_name,
420 + "filesystem.write_latency", NETDATA_EBPF_CHART_TYPE_STACKED, order,
421 + ebpf_create_global_dimension,
422 filesystem_publish_aggregated, NETDATA_EBPF_HIST_MAX_BINS,
423 update_every, NETDATA_EBPF_MODULE_NAME_FILESYSTEM);
424 order++;
@@ -423,11 +427,13 @@ static void ebpf_create_fs_charts(int update_every)
427 snprintfz(chart_name, 63, "%s_open_latency", efp->filesystem);
428 efp->hopen.name = strdupz(chart_name);
429 efp->hopen.title = strdupz(title);
430 + efp->hopen.ctx = NULL;
431 efp->hopen.order = order;
432 ebpf_create_chart(NETDATA_FILESYSTEM_FAMILY, efp->hopen.name,
428 - title,
429 - EBPF_COMMON_DIMENSION_CALL, family,
430 - "filesystem.open_latency", NETDATA_EBPF_CHART_TYPE_STACKED, order, ebpf_create_global_dimension,
433 + efp->hopen.title,
434 + EBPF_COMMON_DIMENSION_CALL, efp->family_name,
435 + "filesystem.open_latency", NETDATA_EBPF_CHART_TYPE_STACKED, order,
436 + ebpf_create_global_dimension,
437 filesystem_publish_aggregated, NETDATA_EBPF_HIST_MAX_BINS,
438 update_every, NETDATA_EBPF_MODULE_NAME_FILESYSTEM);
439 order++;
@@ -438,9 +444,10 @@ static void ebpf_create_fs_charts(int update_every)
444 snprintfz(ctx, 63, "filesystem.%s_latency", type);
445 efp->hadditional.name = strdupz(chart_name);
446 efp->hadditional.title = strdupz(title);
447 + efp->hadditional.ctx = strdupz(ctx);
448 efp->hadditional.order = order;
442 - ebpf_create_chart(NETDATA_FILESYSTEM_FAMILY, efp->hadditional.name, title,
443 - EBPF_COMMON_DIMENSION_CALL, family,
449 + ebpf_create_chart(NETDATA_FILESYSTEM_FAMILY, efp->hadditional.name, efp->hadditional.title,
450 + EBPF_COMMON_DIMENSION_CALL, efp->family_name,
451 ctx, NETDATA_EBPF_CHART_TYPE_STACKED, order, ebpf_create_global_dimension,
452 filesystem_publish_aggregated, NETDATA_EBPF_HIST_MAX_BINS,
453 update_every, NETDATA_EBPF_MODULE_NAME_FILESYSTEM);
@@ -448,6 +455,8 @@ static void ebpf_create_fs_charts(int update_every)
455 efp->flags |= NETDATA_FILESYSTEM_FLAG_CHART_CREATED;
456 }
457 }
458 +
459 + fflush(stdout);
460 }
461
462 /**
@@ -459,6 +468,7 @@ static void ebpf_create_fs_charts(int update_every)
468 */
469 int ebpf_filesystem_initialize_ebpf_data(ebpf_module_t *em)
470 {
471 + pthread_mutex_lock(&lock);
472 int i;
473 const char *saved_name = em->thread_name;
474 uint64_t kernels = em->kernels;
@@ -476,6 +486,8 @@ int ebpf_filesystem_initialize_ebpf_data(ebpf_module_t *em)
486 if (!efp->probe_links) {
487 em->thread_name = saved_name;
488 em->kernels = kernels;
489 + em->maps = NULL;
490 + pthread_mutex_unlock(&lock);
491 return -1;
492 }
493 }
@@ -494,9 +506,7 @@ int ebpf_filesystem_initialize_ebpf_data(ebpf_module_t *em)
506 }
507 #endif
508 efp->flags |= NETDATA_FILESYSTEM_FLAG_HAS_PARTITION;
497 - pthread_mutex_lock(&lock);
509 ebpf_update_kernel_memory(&plugin_statistics, efp->fs_maps, EBPF_ACTION_STAT_ADD);
499 - pthread_mutex_unlock(&lock);
510
511 // Nedeed for filesystems like btrfs
512 if ((efp->flags & NETDATA_FILESYSTEM_FILL_ADDRESS_TABLE) && (efp->addresses.function)) {
@@ -506,6 +516,7 @@ int ebpf_filesystem_initialize_ebpf_data(ebpf_module_t *em)
516 efp->flags &= ~NETDATA_FILESYSTEM_LOAD_EBPF_PROGRAM;
517 }
518 em->thread_name = saved_name;
519 + pthread_mutex_unlock(&lock);
520 em->kernels = kernels;
521 em->maps = NULL;
522
@@ -616,43 +627,88 @@ void ebpf_filesystem_cleanup_ebpf_data()
627 ebpf_filesystem_partitions_t *efp = &localfs[i];
628 if (efp->probe_links) {
629 freez(efp->family_name);
630 + efp->family_name = NULL;
631
632 freez(efp->hread.name);
633 + efp->hread.name = NULL;
634 freez(efp->hread.title);
635 + efp->hread.title = NULL;
636
637 freez(efp->hwrite.name);
638 + efp->hwrite.name = NULL;
639 freez(efp->hwrite.title);
640 + efp->hwrite.title = NULL;
641
642 freez(efp->hopen.name);
643 + efp->hopen.name = NULL;
644 freez(efp->hopen.title);
645 + efp->hopen.title = NULL;
646
647 freez(efp->hadditional.name);
648 + efp->hadditional.name = NULL;
649 freez(efp->hadditional.title);
650 + efp->hadditional.title = NULL;
651 + freez(efp->hadditional.ctx);
652 + efp->hadditional.ctx = NULL;
653 }
654 }
655 }
656
657 /**
636 - * Filesystem Free
658 + * Obsolete global
659 *
638 - * Cleanup variables after child threads to stop
660 + * Obsolete global charts created by thread.
661 *
640 - * @param ptr thread data.
662 + * @param em a pointer to `struct ebpf_module`
663 */
642 -static void ebpf_filesystem_free(ebpf_module_t *em)
664 +static void ebpf_obsolete_filesystem_global(ebpf_module_t *em)
665 {
644 - pthread_mutex_lock(&ebpf_exit_cleanup);
645 - em->enabled = NETDATA_THREAD_EBPF_STOPPING;
646 - pthread_mutex_unlock(&ebpf_exit_cleanup);
647 -
648 - ebpf_filesystem_cleanup_ebpf_data();
649 - if (dimensions)
650 - ebpf_histogram_dimension_cleanup(dimensions, NETDATA_EBPF_HIST_MAX_BINS);
651 - freez(filesystem_hash_values);
666 + int i;
667 + for (i = 0; localfs[i].filesystem; i++) {
668 + ebpf_filesystem_partitions_t *efp = &localfs[i];
669 + if (!efp->objects)
670 + continue;
671
653 - pthread_mutex_lock(&ebpf_exit_cleanup);
654 - em->enabled = NETDATA_THREAD_EBPF_STOPPED;
655 - pthread_mutex_unlock(&ebpf_exit_cleanup);
672 + ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY,
673 + efp->hread.name,
674 + efp->hread.title,
675 + EBPF_COMMON_DIMENSION_CALL,
676 + efp->family_name,
677 + NETDATA_EBPF_CHART_TYPE_STACKED,
678 + "filesystem.read_latency",
679 + efp->hread.order,
680 + em->update_every);
681 +
682 + ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY,
683 + efp->hwrite.name,
684 + efp->hwrite.title,
685 + EBPF_COMMON_DIMENSION_CALL,
686 + efp->family_name,
687 + NETDATA_EBPF_CHART_TYPE_STACKED,
688 + "filesystem.write_latency",
689 + efp->hwrite.order,
690 + em->update_every);
691 +
692 + ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY,
693 + efp->hopen.name,
694 + efp->hopen.title,
695 + EBPF_COMMON_DIMENSION_CALL,
696 + efp->family_name,
697 + NETDATA_EBPF_CHART_TYPE_STACKED,
698 + "filesystem.open_latency",
699 + efp->hopen.order,
700 + em->update_every);
701 +
702 + ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY,
703 + efp->hadditional.name,
704 + efp->hadditional.title,
705 + EBPF_COMMON_DIMENSION_CALL,
706 + efp->family_name,
707 + NETDATA_EBPF_CHART_TYPE_STACKED,
708 + efp->hadditional.ctx,
709 + efp->hadditional.order,
710 + em->update_every);
711 + }
712 }
713
714 /**
@@ -665,7 +721,39 @@ static void ebpf_filesystem_free(ebpf_module_t *em)
721 static void ebpf_filesystem_exit(void *ptr)
722 {
723 ebpf_module_t *em = (ebpf_module_t *)ptr;
668 - ebpf_filesystem_free(em);
724 +
725 + if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
726 + pthread_mutex_lock(&lock);
727 + ebpf_obsolete_filesystem_global(em);
728 +
729 + pthread_mutex_unlock(&lock);
730 + fflush(stdout);
731 + }
732 +
733 + ebpf_filesystem_cleanup_ebpf_data();
734 + if (dimensions) {
735 + ebpf_histogram_dimension_cleanup(dimensions, NETDATA_EBPF_HIST_MAX_BINS);
736 + dimensions = NULL;
737 + }
738 +
739 + freez(filesystem_hash_values);
740 +
741 + int i;
742 + for (i = 0; localfs[i].filesystem; i++) {
743 + ebpf_filesystem_partitions_t *efp = &localfs[i];
744 + if (!efp->probe_links)
745 + continue;
746 +
747 + ebpf_unload_legacy_code(efp->objects, efp->probe_links);
748 + efp->objects = NULL;
749 + efp->probe_links = NULL;
750 + efp->flags = NETDATA_FILESYSTEM_FLAG_NO_PARTITION;
751 + }
752 +
753 + pthread_mutex_lock(&ebpf_exit_cleanup);
754 + em->enabled = NETDATA_THREAD_EBPF_STOPPED;
755 + ebpf_update_stats(&plugin_statistics, em);
756 + pthread_mutex_unlock(&ebpf_exit_cleanup);
757 }
758
759 /*****************************************************************
@@ -819,7 +907,9 @@ static void filesystem_collector(ebpf_module_t *em)
907 heartbeat_t hb;
908 heartbeat_init(&hb);
909 int counter = update_every - 1;
822 - while (!ebpf_exit_plugin) {
910 + uint32_t running_time = 0;
911 + uint32_t lifetime = em->lifetime;
912 + while (!ebpf_exit_plugin && running_time < lifetime) {
913 (void)heartbeat_next(&hb, USEC_PER_SEC);
914
915 if (ebpf_exit_plugin || ++counter != update_every)
@@ -833,6 +923,15 @@ static void filesystem_collector(ebpf_module_t *em)
923 ebpf_histogram_send_data();
924
925 pthread_mutex_unlock(&lock);
926 +
927 + pthread_mutex_lock(&ebpf_exit_cleanup);
928 + if (running_time && !em->running_time)
929 + running_time = update_every;
930 + else
931 + running_time += update_every;
932 +
933 + em->running_time = running_time;
934 + pthread_mutex_unlock(&ebpf_exit_cleanup);
935 }
936 }
937
collectors/ebpf.plugin/ebpf_filesystem.h
+2 -1
@@ -3,8 +3,9 @@
3 #ifndef NETDATA_EBPF_FILESYSTEM_H
4 #define NETDATA_EBPF_FILESYSTEM_H 1
5
6 -// Module name
6 +// Module name & description
7 #define NETDATA_EBPF_MODULE_NAME_FILESYSTEM "filesystem"
8 +#define NETDATA_EBPF_FS_MODULE_DESC "Monitor filesystem latency for: btrfs, ext4, nfs, xfs and zfs."
9
10 #include "ebpf.h"
11 #ifdef LIBBPF_MAJOR_VERSION
collectors/ebpf.plugin/ebpf_functions.c new
+419
@@ -0,0 +1,419 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "ebpf.h"
4 +#include "ebpf_functions.h"
5 +
6 +/*****************************************************************
7 + * EBPF SELECT MODULE
8 + *****************************************************************/
9 +
10 +/**
11 + * Select Module
12 + *
13 + * @param thread_name name of the thread we are looking for.
14 + *
15 + * @return it returns a pointer for the module that has thread_name on success or NULL otherwise.
16 + */
17 +ebpf_module_t *ebpf_functions_select_module(const char *thread_name) {
18 + int i;
19 + for (i = 0; i < EBPF_MODULE_FUNCTION_IDX; i++) {
20 + if (strcmp(ebpf_modules[i].thread_name, thread_name) == 0) {
21 + return &ebpf_modules[i];
22 + }
23 + }
24 +
25 + return NULL;
26 +}
27 +
28 +/*****************************************************************
29 + * EBPF HELP FUNCTIONS
30 + *****************************************************************/
31 +
32 +/**
33 + * Thread Help
34 + *
35 + * Shows help with all options accepted by thread function.
36 + *
37 + * @param transaction the transaction id that Netdata sent for this function execution
38 +*/
39 +static void ebpf_function_thread_manipulation_help(const char *transaction) {
40 + pthread_mutex_lock(&lock);
41 + pluginsd_function_result_begin_to_stdout(transaction, HTTP_RESP_OK, "text/plain", now_realtime_sec() + 3600);
42 + fprintf(stdout, "%s",
43 + "ebpf.plugin / thread\n"
44 + "\n"
45 + "Function `thread` allows user to control eBPF threads.\n"
46 + "\n"
47 + "The following filters are supported:\n"
48 + "\n"
49 + " thread:NAME\n"
50 + " Shows information for the thread NAME. Names are listed inside `ebpf.d.conf`.\n"
51 + "\n"
52 + " enable:NAME:PERIOD\n"
53 + " Enable a specific thread named `NAME` to run a specific PERIOD in seconds. When PERIOD is not\n"
54 + " specified plugin will use the default 300 seconds\n"
55 + "\n"
56 + " disable:NAME\n"
57 + " Disable a sp.\n"
58 + "\n"
59 + "Filters can be combined. Each filter can be given only one time.\n"
60 + "Process thread is not controlled by functions until we finish the creation of functions per thread..\n"
61 + );
62 + pluginsd_function_result_end_to_stdout();
63 + fflush(stdout);
64 + pthread_mutex_unlock(&lock);
65 +}
66 +
67 +
68 +/*****************************************************************
69 + * EBPF ERROR FUNCTIONS
70 + *****************************************************************/
71 +
72 +/**
73 + * Function error
74 + *
75 + * Show error when a wrong function is given
76 + *
77 + * @param transaction the transaction id that Netdata sent for this function execution
78 + * @param code the error code to show with the message.
79 + * @param msg the error message
80 + */
81 +static void ebpf_function_error(const char *transaction, int code, const char *msg) {
82 + char buffer[PLUGINSD_LINE_MAX + 1];
83 + json_escape_string(buffer, msg, PLUGINSD_LINE_MAX);
84 +
85 + pluginsd_function_result_begin_to_stdout(transaction, code, "application/json", now_realtime_sec());
86 + fprintf(stdout, "{\"status\":%d,\"error_message\":\"%s\"}", code, buffer);
87 + pluginsd_function_result_end_to_stdout();
88 +}
89 +
90 +/*****************************************************************
91 + * EBPF THREAD FUNCTION
92 + *****************************************************************/
93 +
94 +/**
95 + * Function enable
96 + *
97 + * Enable a specific thread.
98 + *
99 + * @param transaction the transaction id that Netdata sent for this function execution
100 + * @param function function name and arguments given to thread.
101 + * @param line_buffer buffer used to parse args
102 + * @param line_max Number of arguments given
103 + * @param timeout The function timeout
104 + * @param em The structure with thread information
105 + */
106 +static void ebpf_function_thread_manipulation(const char *transaction,
107 + char *function __maybe_unused,
108 + char *line_buffer __maybe_unused,
109 + int line_max __maybe_unused,
110 + int timeout __maybe_unused,
111 + ebpf_module_t *em)
112 +{
113 + char *words[PLUGINSD_MAX_WORDS] = { NULL };
114 + char message[512];
115 + uint32_t show_specific_thread = 0;
116 + size_t num_words = quoted_strings_splitter_pluginsd(function, words, PLUGINSD_MAX_WORDS);
117 + for(int i = 1; i < PLUGINSD_MAX_WORDS ;i++) {
118 + const char *keyword = get_word(words, num_words, i);
119 + if (!keyword)
120 + break;
121 +
122 + ebpf_module_t *lem;
123 + if(strncmp(keyword, EBPF_THREADS_ENABLE_CATEGORY, sizeof(EBPF_THREADS_ENABLE_CATEGORY) -1) == 0) {
124 + char thread_name[128];
125 + int period = -1;
126 + const char *name = &keyword[sizeof(EBPF_THREADS_ENABLE_CATEGORY) - 1];
127 + char *separator = strchr(name, ':');
128 + if (separator) {
129 + strncpyz(thread_name, name, separator - name);
130 + period = str2i(++separator);
131 + } else {
132 + strncpyz(thread_name, name, strlen(name));
133 + }
134 +
135 + lem = ebpf_functions_select_module(thread_name);
136 + if (!lem) {
137 + snprintfz(message, 511, "%s%s", EBPF_PLUGIN_THREAD_FUNCTION_ERROR_THREAD_NOT_FOUND, name);
138 + ebpf_function_error(transaction, HTTP_RESP_NOT_FOUND, message);
139 + return;
140 + }
141 +
142 + pthread_mutex_lock(&ebpf_exit_cleanup);
143 + if (lem->enabled > NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
144 + struct netdata_static_thread *st = lem->thread;
145 + // Load configuration again
146 + ebpf_update_module(lem, default_btf, running_on_kernel, isrh);
147 +
148 + // another request for thread that already ran, cleanup and restart
149 + if (st->thread)
150 + freez(st->thread);
151 +
152 + if (period <= 0)
153 + period = EBPF_DEFAULT_LIFETIME;
154 +
155 + st->thread = mallocz(sizeof(netdata_thread_t));
156 + lem->enabled = NETDATA_THREAD_EBPF_FUNCTION_RUNNING;
157 + lem->lifetime = period;
158 +
159 +#ifdef NETDATA_INTERNAL_CHECKS
160 + netdata_log_info("Starting thread %s with lifetime = %d", thread_name, period);
161 +#endif
162 +
163 + netdata_thread_create(st->thread, st->name, NETDATA_THREAD_OPTION_DEFAULT,
164 + st->start_routine, lem);
165 + } else {
166 + lem->running_time = 0;
167 + if (period > 0) // user is modifying period to run
168 + lem->lifetime = period;
169 +#ifdef NETDATA_INTERNAL_CHECKS
170 + netdata_log_info("Thread %s had lifetime updated for %d", thread_name, period);
171 +#endif
172 + }
173 + pthread_mutex_unlock(&ebpf_exit_cleanup);
174 + } else if(strncmp(keyword, EBPF_THREADS_DISABLE_CATEGORY, sizeof(EBPF_THREADS_DISABLE_CATEGORY) -1) == 0) {
175 + const char *name = &keyword[sizeof(EBPF_THREADS_DISABLE_CATEGORY) - 1];
176 + lem = ebpf_functions_select_module(name);
177 + if (!lem) {
178 + snprintfz(message, 511, "%s%s", EBPF_PLUGIN_THREAD_FUNCTION_ERROR_THREAD_NOT_FOUND, name);
179 + ebpf_function_error(transaction, HTTP_RESP_NOT_FOUND, message);
180 + return;
181 + }
182 +
183 + pthread_mutex_lock(&ebpf_exit_cleanup);
184 + if (lem->enabled < NETDATA_THREAD_EBPF_STOPPING && lem->thread->thread) {
185 + lem->lifetime = 0;
186 + lem->running_time = lem->update_every;
187 + netdata_thread_cancel(*lem->thread->thread);
188 + }
189 + pthread_mutex_unlock(&ebpf_exit_cleanup);
190 + } else if(strncmp(keyword, EBPF_THREADS_SELECT_THREAD, sizeof(EBPF_THREADS_SELECT_THREAD) -1) == 0) {
191 + const char *name = &keyword[sizeof(EBPF_THREADS_SELECT_THREAD) - 1];
192 + lem = ebpf_functions_select_module(name);
193 + if (!lem) {
194 + snprintfz(message, 511, "%s%s", EBPF_PLUGIN_THREAD_FUNCTION_ERROR_THREAD_NOT_FOUND, name);
195 + ebpf_function_error(transaction, HTTP_RESP_NOT_FOUND, message);
196 + return;
197 + }
198 +
199 + show_specific_thread |= 1<<lem->thread_id;
200 + } else if(strncmp(keyword, "help", 4) == 0) {
201 + ebpf_function_thread_manipulation_help(transaction);
202 + return;
203 + }
204 + }
205 +
206 + time_t expires = now_realtime_sec() + em->update_every;
207 +
208 + BUFFER *wb = buffer_create(PLUGINSD_LINE_MAX, NULL);
209 + buffer_json_initialize(wb, "\"", "\"", 0, true, false);
210 + buffer_json_member_add_uint64(wb, "status", HTTP_RESP_OK);
211 + buffer_json_member_add_string(wb, "type", "table");
212 + buffer_json_member_add_time_t(wb, "update_every", em->update_every);
213 + buffer_json_member_add_string(wb, "help", EBPF_PLUGIN_THREAD_FUNCTION_DESCRIPTION);
214 +
215 + // Collect data
216 + buffer_json_member_add_array(wb, "data");
217 + int i;
218 + for (i = 0; i < EBPF_MODULE_FUNCTION_IDX; i++) {
219 + if (show_specific_thread && !(show_specific_thread & 1<<i))
220 + continue;
221 +
222 + ebpf_module_t *wem = &ebpf_modules[i];
223 + buffer_json_add_array_item_array(wb);
224 +
225 + // IMPORTANT!
226 + // THE ORDER SHOULD BE THE SAME WITH THE FIELDS!
227 +
228 + // thread name
229 + buffer_json_add_array_item_string(wb, wem->thread_name);
230 +
231 + // description
232 + buffer_json_add_array_item_string(wb, wem->thread_description);
233 + // Either it is not running or received a disabled signal and it is stopping.
234 + if (wem->enabled > NETDATA_THREAD_EBPF_FUNCTION_RUNNING ||
235 + (!wem->lifetime && (int)wem->running_time == wem->update_every)) {
236 + // status
237 + buffer_json_add_array_item_string(wb, EBPF_THREAD_STATUS_STOPPED);
238 +
239 + // Time remaining
240 + buffer_json_add_array_item_uint64(wb, 0);
241 +
242 + // action
243 + buffer_json_add_array_item_string(wb, "NULL");
244 + } else {
245 + // status
246 + buffer_json_add_array_item_string(wb, EBPF_THREAD_STATUS_RUNNING);
247 +
248 + // Time remaining
249 + buffer_json_add_array_item_uint64(wb, (wem->lifetime) ? (wem->lifetime - wem->running_time) : 0);
250 +
251 + // action
252 + buffer_json_add_array_item_string(wb, "Enabled/Disabled");
253 + }
254 +
255 + buffer_json_array_close(wb);
256 + }
257 +
258 + buffer_json_array_close(wb); // data
259 +
260 + buffer_json_member_add_object(wb, "columns");
261 + {
262 + int fields_id = 0;
263 +
264 + // IMPORTANT!
265 + // THE ORDER SHOULD BE THE SAME WITH THE VALUES!
266 + buffer_rrdf_table_add_field(wb, fields_id++, "Thread", "Thread Name", RRDF_FIELD_TYPE_STRING,
267 + RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE, 0, NULL, NAN,
268 + RRDF_FIELD_SORT_ASCENDING, NULL, RRDF_FIELD_SUMMARY_COUNT,
269 + RRDF_FIELD_FILTER_MULTISELECT,
270 + RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_STICKY, NULL);
271 +
272 + buffer_rrdf_table_add_field(wb, fields_id++, "Description", "Thread Desc", RRDF_FIELD_TYPE_STRING,
273 + RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE, 0, NULL, NAN,
274 + RRDF_FIELD_SORT_ASCENDING, NULL, RRDF_FIELD_SUMMARY_COUNT,
275 + RRDF_FIELD_FILTER_MULTISELECT,
276 + RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_STICKY, NULL);
277 +
278 + buffer_rrdf_table_add_field(wb, fields_id++, "Status", "Thread Status", RRDF_FIELD_TYPE_STRING,
279 + RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE, 0, NULL, NAN,
280 + RRDF_FIELD_SORT_ASCENDING, NULL, RRDF_FIELD_SUMMARY_COUNT,
281 + RRDF_FIELD_FILTER_MULTISELECT,
282 + RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_STICKY, NULL);
283 +
284 + buffer_rrdf_table_add_field(wb, fields_id++, "Time", "Time Remaining", RRDF_FIELD_TYPE_INTEGER,
285 + RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NUMBER, 0, NULL,
286 + NAN, RRDF_FIELD_SORT_ASCENDING, NULL, RRDF_FIELD_SUMMARY_COUNT,
287 + RRDF_FIELD_FILTER_MULTISELECT,
288 + RRDF_FIELD_OPTS_NONE, NULL);
289 +
290 + buffer_rrdf_table_add_field(wb, fields_id++, "Action", "Thread Action", RRDF_FIELD_TYPE_STRING,
291 + RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE, 0, NULL, NAN,
292 + RRDF_FIELD_SORT_ASCENDING, NULL, RRDF_FIELD_SUMMARY_COUNT,
293 + RRDF_FIELD_FILTER_MULTISELECT,
294 + RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_STICKY, NULL);
295 + }
296 + buffer_json_object_close(wb); // columns
297 +
298 + buffer_json_member_add_string(wb, "default_sort_column", "Thread");
299 +
300 + buffer_json_member_add_object(wb, "charts");
301 + {
302 + // Threads
303 + buffer_json_member_add_object(wb, "eBPFThreads");
304 + {
305 + buffer_json_member_add_string(wb, "name", "Threads");
306 + buffer_json_member_add_string(wb, "type", "line");
307 + buffer_json_member_add_array(wb, "columns");
308 + {
309 + buffer_json_add_array_item_string(wb, "Threads");
310 + }
311 + buffer_json_array_close(wb);
312 + }
313 + buffer_json_object_close(wb);
314 +
315 + // Life Time
316 + buffer_json_member_add_object(wb, "eBPFLifeTime");
317 + {
318 + buffer_json_member_add_string(wb, "name", "LifeTime");
319 + buffer_json_member_add_string(wb, "type", "line");
320 + buffer_json_member_add_array(wb, "columns");
321 + {
322 + buffer_json_add_array_item_string(wb, "Threads");
323 + buffer_json_add_array_item_string(wb, "Time");
324 + }
325 + buffer_json_array_close(wb);
326 + }
327 + buffer_json_object_close(wb);
328 + }
329 + buffer_json_object_close(wb); // charts
330 +
331 + // Do we use only on fields that can be groupped?
332 + buffer_json_member_add_object(wb, "group_by");
333 + {
334 + // group by Status
335 + buffer_json_member_add_object(wb, "Status");
336 + {
337 + buffer_json_member_add_string(wb, "name", "Thread status");
338 + buffer_json_member_add_array(wb, "columns");
339 + {
340 + buffer_json_add_array_item_string(wb, "Status");
341 + }
342 + buffer_json_array_close(wb);
343 + }
344 + buffer_json_object_close(wb);
345 + }
346 + buffer_json_object_close(wb); // group_by
347 +
348 + buffer_json_member_add_time_t(wb, "expires", expires);
349 + buffer_json_finalize(wb);
350 +
351 + // Lock necessary to avoid race condition
352 + pthread_mutex_lock(&lock);
353 + pluginsd_function_result_begin_to_stdout(transaction, HTTP_RESP_OK, "application/json", expires);
354 +
355 + fwrite(buffer_tostring(wb), buffer_strlen(wb), 1, stdout);
356 +
357 + pluginsd_function_result_end_to_stdout();
358 + fflush(stdout);
359 + pthread_mutex_unlock(&lock);
360 +
361 + buffer_free(wb);
362 +}
363 +
364 +
365 +/*****************************************************************
366 + * EBPF FUNCTION THREAD
367 + *****************************************************************/
368 +
369 +/**
370 + * FUNCTION thread.
371 + *
372 + * @param ptr a `ebpf_module_t *`.
373 + *
374 + * @return always NULL.
375 + */
376 +void *ebpf_function_thread(void *ptr)
377 +{
378 + ebpf_module_t *em = (ebpf_module_t *)ptr;
379 + char buffer[PLUGINSD_LINE_MAX + 1];
380 +
381 + char *s = NULL;
382 + while(!ebpf_exit_plugin && (s = fgets(buffer, PLUGINSD_LINE_MAX, stdin))) {
383 + char *words[PLUGINSD_MAX_WORDS] = { NULL };
384 + size_t num_words = quoted_strings_splitter_pluginsd(buffer, words, PLUGINSD_MAX_WORDS);
385 +
386 + const char *keyword = get_word(words, num_words, 0);
387 +
388 + if(keyword && strcmp(keyword, PLUGINSD_KEYWORD_FUNCTION) == 0) {
389 + char *transaction = get_word(words, num_words, 1);
390 + char *timeout_s = get_word(words, num_words, 2);
391 + char *function = get_word(words, num_words, 3);
392 +
393 + if(!transaction || !*transaction || !timeout_s || !*timeout_s || !function || !*function) {
394 + netdata_log_error("Received incomplete %s (transaction = '%s', timeout = '%s', function = '%s'). Ignoring it.",
395 + keyword,
396 + transaction?transaction:"(unset)",
397 + timeout_s?timeout_s:"(unset)",
398 + function?function:"(unset)");
399 + }
400 + else {
401 + int timeout = str2i(timeout_s);
402 + if (!strncmp(function, EBPF_FUNCTION_THREAD, sizeof(EBPF_FUNCTION_THREAD) - 1))
403 + ebpf_function_thread_manipulation(transaction,
404 + function,
405 + buffer,
406 + PLUGINSD_LINE_MAX + 1,
407 + timeout,
408 + em);
409 + else
410 + ebpf_function_error(transaction,
411 + HTTP_RESP_NOT_FOUND,
412 + "No function with this name found in ebpf.plugin.");
413 + }
414 + }
415 + else
416 + netdata_log_error("Received unknown command: %s", keyword ? keyword : "(unset)");
417 + }
418 + return NULL;
419 +}
collectors/ebpf.plugin/ebpf_functions.h new
+29
@@ -0,0 +1,29 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_EBPF_FUNCTIONS_H
4 +#define NETDATA_EBPF_FUNCTIONS_H 1
5 +
6 +// configuration file & description
7 +#define NETDATA_DIRECTORY_FUNCTIONS_CONFIG_FILE "functions.conf"
8 +#define NETDATA_EBPF_FUNCTIONS_MODULE_DESC "Show information about current function status."
9 +
10 +// function list
11 +#define EBPF_FUNCTION_THREAD "ebpf_thread"
12 +
13 +#define EBPF_PLUGIN_THREAD_FUNCTION_DESCRIPTION "Detailed information about eBPF threads."
14 +#define EBPF_PLUGIN_THREAD_FUNCTION_ERROR_THREAD_NOT_FOUND "ebpf.plugin does not have thread named "
15 +
16 +#define EBPF_PLUGIN_FUNCTIONS(NAME, DESC) do { \
17 + fprintf(stdout, PLUGINSD_KEYWORD_FUNCTION " \"" NAME "\" 10 \"%s\"\n", DESC); \
18 +} while(0)
19 +
20 +#define EBPF_THREADS_SELECT_THREAD "thread:"
21 +#define EBPF_THREADS_ENABLE_CATEGORY "enable:"
22 +#define EBPF_THREADS_DISABLE_CATEGORY "disable:"
23 +
24 +#define EBPF_THREAD_STATUS_RUNNING "running"
25 +#define EBPF_THREAD_STATUS_STOPPED "stopped"
26 +
27 +void *ebpf_function_thread(void *ptr);
28 +
29 +#endif
collectors/ebpf.plugin/ebpf_hardirq.c
+50 -3
@@ -215,6 +215,27 @@ void ebpf_hardirq_release(hardirq_val_t *stat)
215 *
216 *****************************************************************/
217
218 +/**
219 + * Obsolete global
220 + *
221 + * Obsolete global charts created by thread.
222 + *
223 + * @param em a pointer to `struct ebpf_module`
224 + */
225 +static void ebpf_obsolete_hardirq_global(ebpf_module_t *em)
226 +{
227 + ebpf_write_chart_obsolete(NETDATA_EBPF_SYSTEM_GROUP,
228 + "hardirq_latency",
229 + "Hardware IRQ latency",
230 + EBPF_COMMON_DIMENSION_MILLISECONDS,
231 + "interrupts",
232 + NETDATA_EBPF_CHART_TYPE_STACKED,
233 + NULL,
234 + NETDATA_CHART_PRIO_HARDIRQ_LATENCY,
235 + em->update_every
236 + );
237 +}
238 +
239 /**
240 * Hardirq Exit
241 *
@@ -226,8 +247,22 @@ static void hardirq_exit(void *ptr)
247 {
248 ebpf_module_t *em = (ebpf_module_t *)ptr;
249
229 - if (em->objects)
250 + if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
251 + pthread_mutex_lock(&lock);
252 +
253 + ebpf_obsolete_hardirq_global(em);
254 +
255 + pthread_mutex_unlock(&lock);
256 + fflush(stdout);
257 + }
258 +
259 + ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_REMOVE);
260 +
261 + if (em->objects) {
262 ebpf_unload_legacy_code(em->objects, em->probe_links);
263 + em->objects = NULL;
264 + em->probe_links = NULL;
265 + }
266
267 for (int i = 0; hardirq_tracepoints[i].class != NULL; i++) {
268 ebpf_disable_tracepoint(&hardirq_tracepoints[i]);
@@ -235,6 +270,7 @@ static void hardirq_exit(void *ptr)
270
271 pthread_mutex_lock(&ebpf_exit_cleanup);
272 em->enabled = NETDATA_THREAD_EBPF_STOPPED;
273 + ebpf_update_stats(&plugin_statistics, em);
274 pthread_mutex_unlock(&ebpf_exit_cleanup);
275 }
276
@@ -533,7 +569,7 @@ static void hardirq_collector(ebpf_module_t *em)
569 hardirq_create_charts(em->update_every);
570 hardirq_create_static_dims();
571 ebpf_update_stats(&plugin_statistics, em);
536 - ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps);
572 + ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_ADD);
573 pthread_mutex_unlock(&lock);
574
575 // loop and read from published data until ebpf plugin is closed.
@@ -542,7 +578,9 @@ static void hardirq_collector(ebpf_module_t *em)
578 int update_every = em->update_every;
579 int counter = update_every - 1;
580 //This will be cancelled by its parent
545 - while (!ebpf_exit_plugin) {
581 + uint32_t running_time = 0;
582 + uint32_t lifetime = em->lifetime;
583 + while (!ebpf_exit_plugin && running_time < lifetime) {
584 (void)heartbeat_next(&hb, USEC_PER_SEC);
585
586 if (ebpf_exit_plugin || ++counter != update_every)
@@ -561,6 +599,15 @@ static void hardirq_collector(ebpf_module_t *em)
599 write_end_chart();
600
601 pthread_mutex_unlock(&lock);
602 +
603 + pthread_mutex_lock(&ebpf_exit_cleanup);
604 + if (running_time && !em->running_time)
605 + running_time = update_every;
606 + else
607 + running_time += update_every;
608 +
609 + em->running_time = running_time;
610 + pthread_mutex_unlock(&ebpf_exit_cleanup);
611 }
612 }
613
collectors/ebpf.plugin/ebpf_hardirq.h
+3
@@ -3,6 +3,9 @@
3 #ifndef NETDATA_EBPF_HARDIRQ_H
4 #define NETDATA_EBPF_HARDIRQ_H 1
5
6 +// Module description
7 +#define NETDATA_EBPF_HARDIRQ_MODULE_DESC "Show time spent servicing individual hardware interrupt requests (hard IRQs)."
8 +
9 #include <stdint.h>
10 #include "libnetdata/avl/avl.h"
11
collectors/ebpf.plugin/ebpf_mdflush.c
+49 -3
@@ -129,6 +129,26 @@ static inline int ebpf_mdflush_load_and_attach(struct mdflush_bpf *obj, ebpf_mod
129
130 #endif
131
132 +/**
133 + * Obsolete global
134 + *
135 + * Obsolete global charts created by thread.
136 + *
137 + * @param em a pointer to `struct ebpf_module`
138 + */
139 +static void ebpf_obsolete_mdflush_global(ebpf_module_t *em)
140 +{
141 + ebpf_write_chart_obsolete("mdstat",
142 + "mdstat_flush",
143 + "MD flushes",
144 + "flushes",
145 + "flush (eBPF)",
146 + NETDATA_EBPF_CHART_TYPE_STACKED,
147 + NULL,
148 + NETDATA_CHART_PRIO_MDSTAT_FLUSH,
149 + em->update_every);
150 +}
151 +
152 /**
153 * MDflush exit
154 *
@@ -140,11 +160,26 @@ static void mdflush_exit(void *ptr)
160 {
161 ebpf_module_t *em = (ebpf_module_t *)ptr;
162
143 - if (em->objects)
163 + if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
164 + pthread_mutex_lock(&lock);
165 +
166 + ebpf_obsolete_mdflush_global(em);
167 +
168 + pthread_mutex_unlock(&lock);
169 + fflush(stdout);
170 + }
171 +
172 + ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_REMOVE);
173 +
174 + if (em->objects) {
175 ebpf_unload_legacy_code(em->objects, em->probe_links);
176 + em->objects = NULL;
177 + em->probe_links = NULL;
178 + }
179
180 pthread_mutex_lock(&ebpf_exit_cleanup);
181 em->enabled = NETDATA_THREAD_EBPF_STOPPED;
182 + ebpf_update_stats(&plugin_statistics, em);
183 pthread_mutex_unlock(&ebpf_exit_cleanup);
184 }
185
@@ -300,7 +335,7 @@ static void mdflush_collector(ebpf_module_t *em)
335 pthread_mutex_lock(&lock);
336 mdflush_create_charts(update_every);
337 ebpf_update_stats(&plugin_statistics, em);
303 - ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps);
338 + ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_ADD);
339 pthread_mutex_unlock(&lock);
340
341 // loop and read from published data until ebpf plugin is closed.
@@ -308,7 +343,9 @@ static void mdflush_collector(ebpf_module_t *em)
343 heartbeat_init(&hb);
344 int counter = update_every - 1;
345 int maps_per_core = em->maps_per_core;
311 - while (!ebpf_exit_plugin) {
346 + uint32_t running_time = 0;
347 + uint32_t lifetime = em->lifetime;
348 + while (!ebpf_exit_plugin && running_time < lifetime) {
349 (void)heartbeat_next(&hb, USEC_PER_SEC);
350
351 if (ebpf_exit_plugin || ++counter != update_every)
@@ -323,6 +360,15 @@ static void mdflush_collector(ebpf_module_t *em)
360 write_end_chart();
361
362 pthread_mutex_unlock(&lock);
363 +
364 + pthread_mutex_lock(&ebpf_exit_cleanup);
365 + if (running_time && !em->running_time)
366 + running_time = update_every;
367 + else
368 + running_time += update_every;
369 +
370 + em->running_time = running_time;
371 + pthread_mutex_unlock(&ebpf_exit_cleanup);
372 }
373 }
374
collectors/ebpf.plugin/ebpf_mdflush.h
+2 -1
@@ -3,8 +3,9 @@
3 #ifndef NETDATA_EBPF_MDFLUSH_H
4 #define NETDATA_EBPF_MDFLUSH_H 1
5
6 -// Module name
6 +// Module name & description
7 #define NETDATA_EBPF_MODULE_NAME_MDFLUSH "mdflush"
8 +#define NETDATA_EBPF_MD_MODULE_DESC "Show information about multi-device software flushes."
9
10 // charts
11 #define NETDATA_MDFLUSH_GLOBAL_CHART "mdflush"
collectors/ebpf.plugin/ebpf_mount.c
+62 -4
@@ -222,6 +222,36 @@ static inline int ebpf_mount_load_and_attach(struct mount_bpf *obj, ebpf_module_
222 *
223 *****************************************************************/
224
225 +/**
226 + * Obsolete global
227 + *
228 + * Obsolete global charts created by thread.
229 + *
230 + * @param em a pointer to `struct ebpf_module`
231 + */
232 +static void ebpf_obsolete_mount_global(ebpf_module_t *em)
233 +{
234 + ebpf_write_chart_obsolete(NETDATA_EBPF_MOUNT_GLOBAL_FAMILY,
235 + NETDATA_EBPF_MOUNT_CALLS,
236 + "Calls to mount and umount syscalls",
237 + EBPF_COMMON_DIMENSION_CALL,
238 + NETDATA_EBPF_MOUNT_FAMILY,
239 + NETDATA_EBPF_CHART_TYPE_LINE,
240 + NULL,
241 + NETDATA_CHART_PRIO_EBPF_MOUNT_CHARTS,
242 + em->update_every);
243 +
244 + ebpf_write_chart_obsolete(NETDATA_EBPF_MOUNT_GLOBAL_FAMILY,
245 + NETDATA_EBPF_MOUNT_ERRORS,
246 + "Errors to mount and umount file systems",
247 + EBPF_COMMON_DIMENSION_CALL,
248 + NETDATA_EBPF_MOUNT_FAMILY,
249 + NETDATA_EBPF_CHART_TYPE_LINE,
250 + NULL,
251 + NETDATA_CHART_PRIO_EBPF_MOUNT_CHARTS + 1,
252 + em->update_every);
253 +}
254 +
255 /**
256 * Mount Exit
257 *
@@ -233,15 +263,32 @@ static void ebpf_mount_exit(void *ptr)
263 {
264 ebpf_module_t *em = (ebpf_module_t *)ptr;
265
266 + if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
267 + pthread_mutex_lock(&lock);
268 +
269 + ebpf_obsolete_mount_global(em);
270 +
271 + fflush(stdout);
272 + pthread_mutex_unlock(&lock);
273 + }
274 +
275 + ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_REMOVE);
276 +
277 #ifdef LIBBPF_MAJOR_VERSION
237 - if (mount_bpf_obj)
278 + if (mount_bpf_obj) {
279 mount_bpf__destroy(mount_bpf_obj);
280 + mount_bpf_obj = NULL;
281 + }
282 #endif
240 - if (em->objects)
283 + if (em->objects) {
284 ebpf_unload_legacy_code(em->objects, em->probe_links);
285 + em->objects = NULL;
286 + em->probe_links = NULL;
287 + }
288
289 pthread_mutex_lock(&ebpf_exit_cleanup);
290 em->enabled = NETDATA_THREAD_EBPF_STOPPED;
291 + ebpf_update_stats(&plugin_statistics, em);
292 pthread_mutex_unlock(&ebpf_exit_cleanup);
293 }
294
@@ -318,7 +365,9 @@ static void mount_collector(ebpf_module_t *em)
365 int update_every = em->update_every;
366 int counter = update_every - 1;
367 int maps_per_core = em->maps_per_core;
321 - while (!ebpf_exit_plugin) {
368 + uint32_t running_time = 0;
369 + uint32_t lifetime = em->lifetime;
370 + while (!ebpf_exit_plugin && running_time < lifetime) {
371 (void)heartbeat_next(&hb, USEC_PER_SEC);
372 if (ebpf_exit_plugin || ++counter != update_every)
373 continue;
@@ -330,6 +379,15 @@ static void mount_collector(ebpf_module_t *em)
379 ebpf_mount_send_data();
380
381 pthread_mutex_unlock(&lock);
382 +
383 + pthread_mutex_lock(&ebpf_exit_cleanup);
384 + if (running_time && !em->running_time)
385 + running_time = update_every;
386 + else
387 + running_time += update_every;
388 +
389 + em->running_time = running_time;
390 + pthread_mutex_unlock(&ebpf_exit_cleanup);
391 }
392 }
393
@@ -444,7 +502,7 @@ void *ebpf_mount_thread(void *ptr)
502 pthread_mutex_lock(&lock);
503 ebpf_create_mount_charts(em->update_every);
504 ebpf_update_stats(&plugin_statistics, em);
447 - ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps);
505 + ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_ADD);
506 pthread_mutex_unlock(&lock);
507
508 mount_collector(em);
collectors/ebpf.plugin/ebpf_mount.h
+2 -1
@@ -3,8 +3,9 @@
3 #ifndef NETDATA_EBPF_MOUNT_H
4 #define NETDATA_EBPF_MOUNT_H 1
5
6 -// Module name
6 +// Module name & description
7 #define NETDATA_EBPF_MODULE_NAME_MOUNT "mount"
8 +#define NETDATA_EBPF_MOUNT_MODULE_DESC "Show calls to syscalls mount(2) and umount(2)."
9
10 #define NETDATA_EBPF_MOUNT_SYSCALL 2
11
collectors/ebpf.plugin/ebpf_oomkill.c
+118 -4
@@ -44,6 +44,71 @@ static netdata_publish_syscall_t oomkill_publish_aggregated = {.name = "oomkill"
44 .algorithm = "absolute",
45 .next = NULL};
46
47 +static void ebpf_create_specific_oomkill_charts(char *type, int update_every);
48 +
49 +/**
50 + * Obsolete services
51 + *
52 + * Obsolete all service charts created
53 + *
54 + * @param em a pointer to `struct ebpf_module`
55 + */
56 +static void ebpf_obsolete_oomkill_services(ebpf_module_t *em)
57 +{
58 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
59 + NETDATA_OOMKILL_CHART,
60 + "OOM kills. This chart is provided by eBPF plugin.",
61 + EBPF_COMMON_DIMENSION_KILLS,
62 + NETDATA_EBPF_MEMORY_GROUP,
63 + NETDATA_EBPF_CHART_TYPE_LINE,
64 + NULL,
65 + 20191,
66 + em->update_every);
67 +}
68 +
69 +/**
70 + * Obsolete cgroup chart
71 + *
72 + * Send obsolete for all charts created before to close.
73 + *
74 + * @param em a pointer to `struct ebpf_module`
75 + */
76 +static inline void ebpf_obsolete_oomkill_cgroup_charts(ebpf_module_t *em)
77 +{
78 + pthread_mutex_lock(&mutex_cgroup_shm);
79 +
80 + ebpf_obsolete_oomkill_services(em);
81 +
82 + ebpf_cgroup_target_t *ect;
83 + for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
84 + if (ect->systemd)
85 + continue;
86 +
87 + ebpf_create_specific_oomkill_charts(ect->name, em->update_every);
88 + }
89 + pthread_mutex_unlock(&mutex_cgroup_shm);
90 +}
91 +
92 +/**
93 + * Obsolete global
94 + *
95 + * Obsolete global charts created by thread.
96 + *
97 + * @param em a pointer to `struct ebpf_module`
98 + */
99 +static void ebpf_obsolete_oomkill_apps(ebpf_module_t *em)
100 +{
101 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
102 + NETDATA_OOMKILL_CHART,
103 + "OOM kills",
104 + EBPF_COMMON_DIMENSION_KILLS,
105 + "mem",
106 + NETDATA_EBPF_CHART_TYPE_STACKED,
107 + NULL,
108 + 20020,
109 + em->update_every);
110 +}
111 +
112 /**
113 * Clean up the main thread.
114 *
@@ -53,11 +118,30 @@ static void oomkill_cleanup(void *ptr)
118 {
119 ebpf_module_t *em = (ebpf_module_t *)ptr;
120
56 - if (em->objects)
121 + if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
122 + pthread_mutex_lock(&lock);
123 +
124 + if (em->cgroup_charts) {
125 + ebpf_obsolete_oomkill_cgroup_charts(em);
126 + }
127 +
128 + ebpf_obsolete_oomkill_apps(em);
129 +
130 + fflush(stdout);
131 + pthread_mutex_unlock(&lock);
132 + }
133 +
134 + ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_REMOVE);
135 +
136 + if (em->objects) {
137 ebpf_unload_legacy_code(em->objects, em->probe_links);
138 + em->objects = NULL;
139 + em->probe_links = NULL;
140 + }
141
142 pthread_mutex_lock(&ebpf_exit_cleanup);
143 em->enabled = NETDATA_THREAD_EBPF_STOPPED;
144 + ebpf_update_stats(&plugin_statistics, em);
145 pthread_mutex_unlock(&ebpf_exit_cleanup);
146 }
147
@@ -293,6 +377,30 @@ static void ebpf_update_oomkill_cgroup(int32_t *keys, uint32_t total)
377 }
378 }
379
380 +/**
381 + * Update OOMkill period
382 + *
383 + * Update oomkill period according function arguments.
384 + *
385 + * @param running_time current value of running_value.
386 + * @param em the thread main structure.
387 + *
388 + * @return It returns new running_time value.
389 + */
390 +static int ebpf_update_oomkill_period(int running_time, ebpf_module_t *em)
391 +{
392 + pthread_mutex_lock(&ebpf_exit_cleanup);
393 + if (running_time && !em->running_time)
394 + running_time = em->update_every;
395 + else
396 + running_time += em->update_every;
397 +
398 + em->running_time = running_time;
399 + pthread_mutex_unlock(&ebpf_exit_cleanup);
400 +
401 + return running_time;
402 +}
403 +
404 /**
405 * Main loop for this collector.
406 *
@@ -309,7 +417,9 @@ static void oomkill_collector(ebpf_module_t *em)
417 heartbeat_t hb;
418 heartbeat_init(&hb);
419 int counter = update_every - 1;
312 - while (!ebpf_exit_plugin) {
420 + uint32_t running_time = 0;
421 + uint32_t lifetime = em->lifetime;
422 + while (!ebpf_exit_plugin && running_time < lifetime) {
423 (void)heartbeat_next(&hb, USEC_PER_SEC);
424 if (ebpf_exit_plugin || ++counter != update_every)
425 continue;
@@ -317,8 +427,10 @@ static void oomkill_collector(ebpf_module_t *em)
427 counter = 0;
428
429 uint32_t count = oomkill_read_data(keys);
320 - if (!count)
430 + if (!count) {
431 + running_time = ebpf_update_oomkill_period(running_time, em);
432 continue;
433 + }
434
435 pthread_mutex_lock(&collect_data_mutex);
436 pthread_mutex_lock(&lock);
@@ -335,6 +447,8 @@ static void oomkill_collector(ebpf_module_t *em)
447 }
448 pthread_mutex_unlock(&lock);
449 pthread_mutex_unlock(&collect_data_mutex);
450 +
451 + running_time = ebpf_update_oomkill_period(running_time, em);
452 }
453 }
454
@@ -406,7 +520,7 @@ void *ebpf_oomkill_thread(void *ptr)
520
521 pthread_mutex_lock(&lock);
522 ebpf_update_stats(&plugin_statistics, em);
409 - ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps);
523 + ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_ADD);
524 pthread_mutex_unlock(&lock);
525
526 oomkill_collector(em);
collectors/ebpf.plugin/ebpf_oomkill.h
+3
@@ -3,6 +3,9 @@
3 #ifndef NETDATA_EBPF_OOMKILL_H
4 #define NETDATA_EBPF_OOMKILL_H 1
5
6 +// Module description
7 +#define NETDATA_EBPF_OOMKILL_MODULE_DESC "Show OOM kills for all applications recognized via the apps.plugin."
8 +
9 /*****************************************************************
10 * copied from kernel-collectors repo, with modifications needed
11 * for inclusion here.
collectors/ebpf.plugin/ebpf_process.c
+269 -248
@@ -59,20 +59,15 @@ ebpf_process_stat_t *process_stat_vector = NULL;
59 static netdata_syscall_stat_t process_aggregated_data[NETDATA_KEY_PUBLISH_PROCESS_END];
60 static netdata_publish_syscall_t process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_END];
61
62 -int process_enabled = 0;
63 -bool publish_internal_metrics = true;
64 -
62 struct config process_config = { .first_section = NULL,
63 .last_section = NULL,
64 .mutex = NETDATA_MUTEX_INITIALIZER,
65 .index = { .avl_tree = { .root = NULL, .compar = appconfig_section_compare },
66 .rwlock = AVL_LOCK_INITIALIZER } };
67
71 -static char *threads_stat[NETDATA_EBPF_THREAD_STAT_END] = {"total", "running"};
72 -static char *load_event_stat[NETDATA_EBPF_LOAD_STAT_END] = {"legacy", "co-re"};
73 -static char *memlock_stat = {"memory_locked"};
74 -static char *hash_table_stat = {"hash_table"};
75 -static char *hash_table_core[NETDATA_EBPF_LOAD_STAT_END] = {"per_core", "unique"};
68 +#ifdef NETDATA_DEV_MODE
69 +int process_disable_priority;
70 +#endif
71
72 /*****************************************************************
73 *
@@ -427,182 +422,8 @@ static void ebpf_create_global_charts(ebpf_module_t *em)
422 &process_publish_aggregated[NETDATA_KEY_PUBLISH_PROCESS_FORK],
423 2, em->update_every, NETDATA_EBPF_MODULE_NAME_PROCESS);
424 }
430 -}
431 -
432 -/**
433 - * Create chart for Statistic Thread
434 - *
435 - * Write to standard output current values for threads.
436 - *
437 - * @param em a pointer to the structure with the default values.
438 - */
439 -static inline void ebpf_create_statistic_thread_chart(ebpf_module_t *em)
440 -{
441 - ebpf_write_chart_cmd(NETDATA_MONITORING_FAMILY,
442 - NETDATA_EBPF_THREADS,
443 - "Threads info.",
444 - "threads",
445 - NETDATA_EBPF_FAMILY,
446 - NETDATA_EBPF_CHART_TYPE_LINE,
447 - NULL,
448 - 140000,
449 - em->update_every,
450 - NETDATA_EBPF_MODULE_NAME_PROCESS);
451 -
452 - ebpf_write_global_dimension(threads_stat[NETDATA_EBPF_THREAD_STAT_TOTAL],
453 - threads_stat[NETDATA_EBPF_THREAD_STAT_TOTAL],
454 - ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
455 -
456 - ebpf_write_global_dimension(threads_stat[NETDATA_EBPF_THREAD_STAT_RUNNING],
457 - threads_stat[NETDATA_EBPF_THREAD_STAT_RUNNING],
458 - ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
459 -}
460 -
461 -/**
462 - * Create chart for Load Thread
463 - *
464 - * Write to standard output current values for load mode.
465 - *
466 - * @param em a pointer to the structure with the default values.
467 - */
468 -static inline void ebpf_create_statistic_load_chart(ebpf_module_t *em)
469 -{
470 - ebpf_write_chart_cmd(NETDATA_MONITORING_FAMILY,
471 - NETDATA_EBPF_LOAD_METHOD,
472 - "Load info.",
473 - "methods",
474 - NETDATA_EBPF_FAMILY,
475 - NETDATA_EBPF_CHART_TYPE_LINE,
476 - NULL,
477 - 140001,
478 - em->update_every,
479 - NETDATA_EBPF_MODULE_NAME_PROCESS);
480 -
481 - ebpf_write_global_dimension(load_event_stat[NETDATA_EBPF_LOAD_STAT_LEGACY],
482 - load_event_stat[NETDATA_EBPF_LOAD_STAT_LEGACY],
483 - ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
484 -
485 - ebpf_write_global_dimension(load_event_stat[NETDATA_EBPF_LOAD_STAT_CORE],
486 - load_event_stat[NETDATA_EBPF_LOAD_STAT_CORE],
487 - ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
488 -}
489 -
490 -/**
491 - * Create chart for Kernel Memory
492 - *
493 - * Write to standard output current values for allocated memory.
494 - *
495 - * @param em a pointer to the structure with the default values.
496 - */
497 -static inline void ebpf_create_statistic_kernel_memory(ebpf_module_t *em)
498 -{
499 - ebpf_write_chart_cmd(NETDATA_MONITORING_FAMILY,
500 - NETDATA_EBPF_KERNEL_MEMORY,
501 - "Memory allocated for hash tables.",
502 - "bytes",
503 - NETDATA_EBPF_FAMILY,
504 - NETDATA_EBPF_CHART_TYPE_LINE,
505 - NULL,
506 - 140002,
507 - em->update_every,
508 - NETDATA_EBPF_MODULE_NAME_PROCESS);
509 -
510 - ebpf_write_global_dimension(memlock_stat,
511 - memlock_stat,
512 - ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
513 -}
514 -
515 -/**
516 - * Create chart Hash Table
517 - *
518 - * Write to standard output number of hash tables used with this software.
519 - *
520 - * @param em a pointer to the structure with the default values.
521 - */
522 -static inline void ebpf_create_statistic_hash_tables(ebpf_module_t *em)
523 -{
524 - ebpf_write_chart_cmd(NETDATA_MONITORING_FAMILY,
525 - NETDATA_EBPF_HASH_TABLES_LOADED,
526 - "Number of hash tables loaded.",
527 - "hash tables",
528 - NETDATA_EBPF_FAMILY,
529 - NETDATA_EBPF_CHART_TYPE_LINE,
530 - NULL,
531 - 140003,
532 - em->update_every,
533 - NETDATA_EBPF_MODULE_NAME_PROCESS);
534 -
535 - ebpf_write_global_dimension(hash_table_stat,
536 - hash_table_stat,
537 - ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
538 -}
539 -
540 -/**
541 - * Create chart for percpu stats
542 - *
543 - * Write to standard output current values for threads.
544 - *
545 - * @param em a pointer to the structure with the default values.
546 - */
547 -static inline void ebpf_create_statistic_hash_per_core(ebpf_module_t *em)
548 -{
549 - ebpf_write_chart_cmd(NETDATA_MONITORING_FAMILY,
550 - NETDATA_EBPF_HASH_TABLES_PER_CORE,
551 - "How threads are loading hash/array tables.",
552 - "threads",
553 - NETDATA_EBPF_FAMILY,
554 - NETDATA_EBPF_CHART_TYPE_LINE,
555 - NULL,
556 - 140004,
557 - em->update_every,
558 - NETDATA_EBPF_MODULE_NAME_PROCESS);
559 -
560 - ebpf_write_global_dimension(hash_table_core[NETDATA_EBPF_THREAD_PER_CORE],
561 - hash_table_core[NETDATA_EBPF_THREAD_PER_CORE],
562 - ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
563 -
564 - ebpf_write_global_dimension(hash_table_core[NETDATA_EBPF_THREAD_UNIQUE],
565 - hash_table_core[NETDATA_EBPF_THREAD_UNIQUE],
566 - ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
567 -}
568 -
569 -/**
570 - * Update Internal Metric variable
571 - *
572 - * By default eBPF.plugin sends internal metrics for netdata, but user can
573 - * disable this.
574 - *
575 - * The function updates the variable used to send charts.
576 - */
577 -static void update_internal_metric_variable()
578 -{
579 - const char *s = getenv("NETDATA_INTERNALS_MONITORING");
580 - if (s && *s && strcmp(s, "NO") == 0)
581 - publish_internal_metrics = false;
582 -}
583 -
584 -/**
585 - * Create Statistics Charts
586 - *
587 - * Create charts that will show statistics related to eBPF plugin.
588 - *
589 - * @param em a pointer to the structure with the default values.
590 - */
591 -static void ebpf_create_statistic_charts(ebpf_module_t *em)
592 -{
593 - update_internal_metric_variable();
594 - if (!publish_internal_metrics)
595 - return;
425
597 - ebpf_create_statistic_thread_chart(em);
598 -
599 - ebpf_create_statistic_load_chart(em);
600 -
601 - ebpf_create_statistic_kernel_memory(em);
602 -
603 - ebpf_create_statistic_hash_tables(em);
604 -
605 - ebpf_create_statistic_hash_per_core(em);
426 + fflush(stdout);
427 }
428
429 /**
@@ -673,6 +494,206 @@ void ebpf_process_create_apps_charts(struct ebpf_module *em, void *ptr)
494 *
495 *****************************************************************/
496
497 +static void ebpf_obsolete_specific_process_charts(char *type, ebpf_module_t *em);
498 +
499 +/**
500 + * Obsolete services
501 + *
502 + * Obsolete all service charts created
503 + *
504 + * @param em a pointer to `struct ebpf_module`
505 + */
506 +static void ebpf_obsolete_process_services(ebpf_module_t *em)
507 +{
508 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
509 + NETDATA_SYSCALL_APPS_TASK_PROCESS,
510 + "Process started",
511 + EBPF_COMMON_DIMENSION_CALL,
512 + NETDATA_APPS_PROCESS_GROUP,
513 + NETDATA_EBPF_CHART_TYPE_STACKED,
514 + NULL,
515 + 20065,
516 + em->update_every);
517 +
518 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
519 + NETDATA_SYSCALL_APPS_TASK_THREAD,
520 + "Threads started",
521 + EBPF_COMMON_DIMENSION_CALL,
522 + NETDATA_APPS_PROCESS_GROUP,
523 + NETDATA_EBPF_CHART_TYPE_STACKED,
524 + NULL,
525 + 20066,
526 + em->update_every);
527 +
528 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
529 + NETDATA_SYSCALL_APPS_TASK_CLOSE,
530 + "Tasks starts exit process.",
531 + EBPF_COMMON_DIMENSION_CALL,
532 + NETDATA_APPS_PROCESS_GROUP,
533 + NETDATA_EBPF_CHART_TYPE_STACKED,
534 + NULL,
535 + 20067,
536 + em->update_every);
537 +
538 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
539 + NETDATA_SYSCALL_APPS_TASK_EXIT,
540 + "Tasks closed",
541 + EBPF_COMMON_DIMENSION_CALL,
542 + NETDATA_APPS_PROCESS_GROUP,
543 + NETDATA_EBPF_CHART_TYPE_STACKED,
544 + NULL,
545 + 20068,
546 + em->update_every);
547 +
548 + if (em->mode < MODE_ENTRY) {
549 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
550 + NETDATA_SYSCALL_APPS_TASK_ERROR,
551 + "Errors to create process or threads.",
552 + EBPF_COMMON_DIMENSION_CALL,
553 + NETDATA_APPS_PROCESS_GROUP,
554 + NETDATA_EBPF_CHART_TYPE_STACKED,
555 + NULL,
556 + 20069,
557 + em->update_every);
558 + }
559 +}
560 +
561 +/**
562 + * Obsolete cgroup chart
563 + *
564 + * Send obsolete for all charts created before to close.
565 + *
566 + * @param em a pointer to `struct ebpf_module`
567 + */
568 +static inline void ebpf_obsolete_process_cgroup_charts(ebpf_module_t *em) {
569 + pthread_mutex_lock(&mutex_cgroup_shm);
570 +
571 + ebpf_obsolete_process_services(em);
572 +
573 + ebpf_cgroup_target_t *ect;
574 + for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
575 + if (ect->systemd)
576 + continue;
577 +
578 + ebpf_obsolete_specific_process_charts(ect->name, em);
579 + }
580 + pthread_mutex_unlock(&mutex_cgroup_shm);
581 +}
582 +
583 +/**
584 + * Obsolette apps charts
585 + *
586 + * Obsolete apps charts.
587 + *
588 + * @param em a pointer to the structure with the default values.
589 + */
590 +void ebpf_obsolete_process_apps_charts(struct ebpf_module *em)
591 +{
592 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
593 + NETDATA_SYSCALL_APPS_TASK_PROCESS,
594 + "Process started",
595 + EBPF_COMMON_DIMENSION_CALL,
596 + NETDATA_PROCESS_GROUP,
597 + NETDATA_EBPF_CHART_TYPE_STACKED,
598 + NULL,
599 + 20065,
600 + em->update_every);
601 +
602 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
603 + NETDATA_SYSCALL_APPS_TASK_THREAD,
604 + "Threads started",
605 + EBPF_COMMON_DIMENSION_CALL,
606 + NETDATA_PROCESS_GROUP,
607 + NETDATA_EBPF_CHART_TYPE_STACKED,
608 + NULL,
609 + 20066,
610 + em->update_every);
611 +
612 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
613 + NETDATA_SYSCALL_APPS_TASK_EXIT,
614 + "Tasks starts exit process.",
615 + EBPF_COMMON_DIMENSION_CALL,
616 + NETDATA_PROCESS_GROUP,
617 + NETDATA_EBPF_CHART_TYPE_STACKED,
618 + NULL,
619 + 20067,
620 + em->update_every);
621 +
622 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
623 + NETDATA_SYSCALL_APPS_TASK_CLOSE,
624 + "Tasks closed",
625 + EBPF_COMMON_DIMENSION_CALL,
626 + NETDATA_PROCESS_GROUP,
627 + NETDATA_EBPF_CHART_TYPE_STACKED,
628 + NULL,
629 + 20068,
630 + em->update_every);
631 +
632 + if (em->mode < MODE_ENTRY) {
633 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
634 + NETDATA_SYSCALL_APPS_TASK_ERROR,
635 + "Errors to create process or threads.",
636 + EBPF_COMMON_DIMENSION_CALL,
637 + NETDATA_PROCESS_GROUP,
638 + NETDATA_EBPF_CHART_TYPE_STACKED,
639 + NULL,
640 + 20069,
641 + em->update_every);
642 + }
643 +}
644 +
645 +/**
646 + * Obsolete global
647 + *
648 + * Obsolete global charts created by thread.
649 + *
650 + * @param em a pointer to `struct ebpf_module`
651 + */
652 +static void ebpf_obsolete_process_global(ebpf_module_t *em)
653 +{
654 + ebpf_write_chart_obsolete(NETDATA_EBPF_SYSTEM_GROUP,
655 + NETDATA_PROCESS_SYSCALL,
656 + "Start process",
657 + EBPF_COMMON_DIMENSION_CALL,
658 + NETDATA_PROCESS_GROUP,
659 + NETDATA_EBPF_CHART_TYPE_LINE,
660 + NULL,
661 + 21002,
662 + em->update_every);
663 +
664 + ebpf_write_chart_obsolete(NETDATA_EBPF_SYSTEM_GROUP,
665 + NETDATA_EXIT_SYSCALL,
666 + "Exit process",
667 + EBPF_COMMON_DIMENSION_CALL,
668 + NETDATA_PROCESS_GROUP,
669 + NETDATA_EBPF_CHART_TYPE_LINE,
670 + NULL,
671 + 21003,
672 + em->update_every);
673 +
674 + ebpf_write_chart_obsolete(NETDATA_EBPF_SYSTEM_GROUP,
675 + NETDATA_PROCESS_STATUS_NAME,
676 + "Process not closed",
677 + EBPF_COMMON_DIMENSION_DIFFERENCE,
678 + NETDATA_PROCESS_GROUP,
679 + NETDATA_EBPF_CHART_TYPE_LINE,
680 + NULL,
681 + 21004,
682 + em->update_every);
683 +
684 + if (em->mode < MODE_ENTRY) {
685 + ebpf_write_chart_obsolete(NETDATA_EBPF_SYSTEM_GROUP,
686 + NETDATA_PROCESS_ERROR_NAME,
687 + "Fails to create process",
688 + EBPF_COMMON_DIMENSION_CALL,
689 + NETDATA_PROCESS_GROUP,
690 + NETDATA_EBPF_CHART_TYPE_LINE,
691 + NULL,
692 + 21005,
693 + em->update_every);
694 + }
695 +}
696 +
697 /**
698 * Process disable tracepoints
699 *
@@ -708,6 +729,37 @@ static void ebpf_process_exit(void *ptr)
729 {
730 ebpf_module_t *em = (ebpf_module_t *)ptr;
731
732 + if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
733 + pthread_mutex_lock(&lock);
734 + if (em->cgroup_charts) {
735 + ebpf_obsolete_process_cgroup_charts(em);
736 + fflush(stdout);
737 + }
738 +
739 + if (em->apps_charts & NETDATA_EBPF_APPS_FLAG_CHART_CREATED) {
740 + ebpf_obsolete_process_apps_charts(em);
741 + }
742 +
743 + ebpf_obsolete_process_global(em);
744 +
745 +#ifdef NETDATA_DEV_MODE
746 + if (ebpf_aral_process_stat)
747 + ebpf_statistic_obsolete_aral_chart(em, process_disable_priority);
748 +#endif
749 +
750 +
751 + fflush(stdout);
752 + pthread_mutex_unlock(&lock);
753 + }
754 +
755 + ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_REMOVE);
756 +
757 + if (em->objects) {
758 + ebpf_unload_legacy_code(em->objects, em->probe_links);
759 + em->objects = NULL;
760 + em->probe_links = NULL;
761 + }
762 +
763 freez(process_hash_values);
764 freez(process_stat_vector);
765
@@ -716,6 +768,7 @@ static void ebpf_process_exit(void *ptr)
768 pthread_mutex_lock(&ebpf_exit_cleanup);
769 process_pid_fd = -1;
770 em->enabled = NETDATA_THREAD_EBPF_STOPPED;
771 + ebpf_update_stats(&plugin_statistics, em);
772 pthread_mutex_unlock(&ebpf_exit_cleanup);
773 }
774
@@ -740,14 +793,14 @@ static void ebpf_process_sum_cgroup_pids(ebpf_process_stat_t *ps, struct pid_on_
793 memset(&accumulator, 0, sizeof(accumulator));
794
795 while (pids) {
743 - ebpf_process_stat_t *ps = &pids->ps;
796 + ebpf_process_stat_t *pps = &pids->ps;
797
745 - accumulator.exit_call += ps->exit_call;
746 - accumulator.release_call += ps->release_call;
747 - accumulator.create_process += ps->create_process;
748 - accumulator.create_thread += ps->create_thread;
798 + accumulator.exit_call += pps->exit_call;
799 + accumulator.release_call += pps->release_call;
800 + accumulator.create_process += pps->create_process;
801 + accumulator.create_thread += pps->create_thread;
802
750 - accumulator.task_err += ps->task_err;
803 + accumulator.task_err += pps->task_err;
804
805 pids = pids->next;
806 }
@@ -1046,40 +1099,6 @@ void ebpf_process_update_cgroup_algorithm()
1099 }
1100 }
1101
1049 -/**
1050 - * Send Statistic Data
1051 - *
1052 - * Send statistic information to netdata.
1053 - */
1054 -void ebpf_send_statistic_data()
1055 -{
1056 - if (!publish_internal_metrics)
1057 - return;
1058 -
1059 - write_begin_chart(NETDATA_MONITORING_FAMILY, NETDATA_EBPF_THREADS);
1060 - write_chart_dimension(threads_stat[NETDATA_EBPF_THREAD_STAT_TOTAL], (long long)plugin_statistics.threads);
1061 - write_chart_dimension(threads_stat[NETDATA_EBPF_THREAD_STAT_RUNNING], (long long)plugin_statistics.running);
1062 - write_end_chart();
1063 -
1064 - write_begin_chart(NETDATA_MONITORING_FAMILY, NETDATA_EBPF_LOAD_METHOD);
1065 - write_chart_dimension(load_event_stat[NETDATA_EBPF_LOAD_STAT_LEGACY], (long long)plugin_statistics.legacy);
1066 - write_chart_dimension(load_event_stat[NETDATA_EBPF_LOAD_STAT_CORE], (long long)plugin_statistics.core);
1067 - write_end_chart();
1068 -
1069 - write_begin_chart(NETDATA_MONITORING_FAMILY, NETDATA_EBPF_KERNEL_MEMORY);
1070 - write_chart_dimension(memlock_stat, (long long)plugin_statistics.memlock_kern);
1071 - write_end_chart();
1072 -
1073 - write_begin_chart(NETDATA_MONITORING_FAMILY, NETDATA_EBPF_HASH_TABLES_LOADED);
1074 - write_chart_dimension(hash_table_stat, (long long)plugin_statistics.hash_tables);
1075 - write_end_chart();
1076 -
1077 - write_begin_chart(NETDATA_MONITORING_FAMILY, NETDATA_EBPF_HASH_TABLES_PER_CORE);
1078 - write_chart_dimension(hash_table_core[NETDATA_EBPF_THREAD_PER_CORE], (long long)plugin_statistics.hash_percpu);
1079 - write_chart_dimension(hash_table_core[NETDATA_EBPF_THREAD_UNIQUE], (long long)plugin_statistics.hash_unique);
1080 - write_end_chart();
1081 -}
1082 -
1102 /**
1103 * Main loop for this collector.
1104 *
@@ -1092,7 +1111,6 @@ static void process_collector(ebpf_module_t *em)
1111 int publish_global = em->global_charts;
1112 int cgroups = em->cgroup_charts;
1113 pthread_mutex_lock(&ebpf_exit_cleanup);
1095 - int thread_enabled = em->enabled;
1114 process_pid_fd = process_maps[NETDATA_PROCESS_PID_TABLE].map_fd;
1115 pthread_mutex_unlock(&ebpf_exit_cleanup);
1116 if (cgroups)
@@ -1101,7 +1119,9 @@ static void process_collector(ebpf_module_t *em)
1119 int update_every = em->update_every;
1120 int counter = update_every - 1;
1121 int maps_per_core = em->maps_per_core;
1104 - while (!ebpf_exit_plugin) {
1122 + uint32_t running_time = 0;
1123 + uint32_t lifetime = em->lifetime;
1124 + while (!ebpf_exit_plugin && running_time < lifetime) {
1125 usec_t dt = heartbeat_next(&hb, USEC_PER_SEC);
1126 (void)dt;
1127 if (ebpf_exit_plugin)
@@ -1122,28 +1142,35 @@ static void process_collector(ebpf_module_t *em)
1142 }
1143
1144 pthread_mutex_lock(&lock);
1125 - ebpf_send_statistic_data();
1145
1127 - if (thread_enabled == NETDATA_THREAD_EBPF_RUNNING) {
1128 - if (publish_global) {
1129 - ebpf_process_send_data(em);
1130 - }
1146 + if (publish_global) {
1147 + ebpf_process_send_data(em);
1148 + }
1149
1132 - if (apps_enabled & NETDATA_EBPF_APPS_FLAG_CHART_CREATED) {
1133 - ebpf_process_send_apps_data(apps_groups_root_target, em);
1134 - }
1150 + if (apps_enabled & NETDATA_EBPF_APPS_FLAG_CHART_CREATED) {
1151 + ebpf_process_send_apps_data(apps_groups_root_target, em);
1152 + }
1153
1154 #ifdef NETDATA_DEV_MODE
1137 - if (ebpf_aral_process_stat)
1138 - ebpf_send_data_aral_chart(ebpf_aral_process_stat, em);
1155 + if (ebpf_aral_process_stat)
1156 + ebpf_send_data_aral_chart(ebpf_aral_process_stat, em);
1157 #endif
1158
1141 - if (cgroups && shm_ebpf_cgroup.header) {
1142 - ebpf_process_send_cgroup_data(em);
1143 - }
1159 + if (cgroups && shm_ebpf_cgroup.header) {
1160 + ebpf_process_send_cgroup_data(em);
1161 }
1162 +
1163 pthread_mutex_unlock(&lock);
1164 pthread_mutex_unlock(&collect_data_mutex);
1165 +
1166 + pthread_mutex_lock(&ebpf_exit_cleanup);
1167 + if (running_time && !em->running_time)
1168 + running_time = update_every;
1169 + else
1170 + running_time += update_every;
1171 +
1172 + em->running_time = running_time;
1173 + pthread_mutex_unlock(&ebpf_exit_cleanup);
1174 }
1175
1176 fflush(stdout);
@@ -1254,7 +1281,6 @@ void *ebpf_process_thread(void *ptr)
1281 if (ebpf_process_enable_tracepoints()) {
1282 em->enabled = em->global_charts = em->apps_charts = em->cgroup_charts = NETDATA_THREAD_EBPF_STOPPING;
1283 }
1257 - process_enabled = em->enabled;
1284 pthread_mutex_unlock(&ebpf_exit_cleanup);
1285
1286 pthread_mutex_lock(&lock);
@@ -1276,27 +1302,22 @@ void *ebpf_process_thread(void *ptr)
1302 process_aggregated_data, process_publish_aggregated, process_dimension_names, process_id_names,
1303 algorithms, NETDATA_KEY_PUBLISH_PROCESS_END);
1304
1279 - if (process_enabled == NETDATA_THREAD_EBPF_RUNNING) {
1280 - ebpf_create_global_charts(em);
1281 - }
1305 + ebpf_create_global_charts(em);
1306
1307 ebpf_update_stats(&plugin_statistics, em);
1284 - ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps);
1308 + ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_ADD);
1309
1310 #ifdef NETDATA_DEV_MODE
1311 if (ebpf_aral_process_stat)
1288 - ebpf_statistic_create_aral_chart(NETDATA_EBPF_PROC_ARAL_NAME, em);
1312 + process_disable_priority = ebpf_statistic_create_aral_chart(NETDATA_EBPF_PROC_ARAL_NAME, em);
1313 #endif
1314
1291 - ebpf_create_statistic_charts(em);
1292 -
1315 pthread_mutex_unlock(&lock);
1316
1317 process_collector(em);
1318
1319 pthread_mutex_lock(&ebpf_exit_cleanup);
1298 - if (em->enabled == NETDATA_THREAD_EBPF_RUNNING)
1299 - ebpf_update_disabled_plugin_stats(em);
1320 + ebpf_update_disabled_plugin_stats(em);
1321 pthread_mutex_unlock(&ebpf_exit_cleanup);
1322
1323 netdata_thread_cleanup_pop(1);
collectors/ebpf.plugin/ebpf_process.h
+9 -7
@@ -3,8 +3,9 @@
3 #ifndef NETDATA_EBPF_PROCESS_H
4 #define NETDATA_EBPF_PROCESS_H 1
5
6 -// Module name
6 +// Module name & description
7 #define NETDATA_EBPF_MODULE_NAME_PROCESS "process"
8 +#define NETDATA_EBPF_MODULE_PROCESS_DESC "Monitor information about process life. This thread is integrated with apps and cgroup."
9
10 // Groups used on Dashboard
11 #define NETDATA_PROCESS_GROUP "processes"
@@ -41,12 +42,13 @@
42
43 #define NETDATA_EBPF_CGROUP_UPDATE 30
44
44 -// Statistical information
45 -enum netdata_ebpf_thread_stats{
46 - NETDATA_EBPF_THREAD_STAT_TOTAL,
47 - NETDATA_EBPF_THREAD_STAT_RUNNING,
48 -
49 - NETDATA_EBPF_THREAD_STAT_END
45 +enum netdata_ebpf_stats_order {
46 + NETDATA_EBPF_ORDER_STAT_THREADS = 140000,
47 + NETDATA_EBPF_ORDER_STAT_LIFE_TIME,
48 + NETDATA_EBPF_ORDER_STAT_LOAD_METHOD,
49 + NETDATA_EBPF_ORDER_STAT_KERNEL_MEMORY,
50 + NETDATA_EBPF_ORDER_STAT_HASH_TABLES,
51 + NETDATA_EBPF_ORDER_STAT_HASH_CORE
52 };
53
54 enum netdata_ebpf_load_mode_stats{
collectors/ebpf.plugin/ebpf_shm.c
+194 -5
@@ -50,6 +50,10 @@ netdata_ebpf_targets_t shm_targets[] = { {.name = "shmget", .mode = EBPF_LOAD_TR
50 {.name = "shmctl", .mode = EBPF_LOAD_TRAMPOLINE},
51 {.name = NULL, .mode = EBPF_LOAD_TRAMPOLINE}};
52
53 +#ifdef NETDATA_DEV_MODE
54 +int shm_disable_priority;
55 +#endif
56 +
57 #ifdef LIBBPF_MAJOR_VERSION
58 /*****************************************************************
59 *
@@ -288,6 +292,150 @@ static inline int ebpf_shm_load_and_attach(struct shm_bpf *obj, ebpf_module_t *e
292 * FUNCTIONS TO CLOSE THE THREAD
293 *****************************************************************/
294
295 +static void ebpf_obsolete_specific_shm_charts(char *type, int update_every);
296 +
297 +/**
298 + * Obsolete services
299 + *
300 + * Obsolete all service charts created
301 + *
302 + * @param em a pointer to `struct ebpf_module`
303 + */
304 +static void ebpf_obsolete_shm_services(ebpf_module_t *em)
305 +{
306 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
307 + NETDATA_SHMGET_CHART,
308 + "Calls to syscall <code>shmget(2)</code>.",
309 + EBPF_COMMON_DIMENSION_CALL,
310 + NETDATA_APPS_IPC_SHM_GROUP,
311 + NETDATA_EBPF_CHART_TYPE_STACKED,
312 + NULL,
313 + 20191,
314 + em->update_every);
315 +
316 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
317 + NETDATA_SHMAT_CHART,
318 + "Calls to syscall <code>shmat(2)</code>.",
319 + EBPF_COMMON_DIMENSION_CALL,
320 + NETDATA_APPS_IPC_SHM_GROUP,
321 + NETDATA_EBPF_CHART_TYPE_STACKED,
322 + NULL,
323 + 20192,
324 + em->update_every);
325 +
326 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
327 + NETDATA_SHMDT_CHART,
328 + "Calls to syscall <code>shmdt(2)</code>.",
329 + EBPF_COMMON_DIMENSION_CALL,
330 + NETDATA_APPS_IPC_SHM_GROUP,
331 + NETDATA_EBPF_CHART_TYPE_STACKED,
332 + NULL,
333 + 20193,
334 + em->update_every);
335 +
336 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
337 + NETDATA_SHMCTL_CHART,
338 + "Calls to syscall <code>shmctl(2)</code>.",
339 + EBPF_COMMON_DIMENSION_CALL,
340 + NETDATA_APPS_IPC_SHM_GROUP,
341 + NETDATA_EBPF_CHART_TYPE_STACKED,
342 + NULL,
343 + 20193,
344 + em->update_every);
345 +}
346 +
347 +/**
348 + * Obsolete cgroup chart
349 + *
350 + * Send obsolete for all charts created before to close.
351 + *
352 + * @param em a pointer to `struct ebpf_module`
353 + */
354 +static inline void ebpf_obsolete_shm_cgroup_charts(ebpf_module_t *em) {
355 + pthread_mutex_lock(&mutex_cgroup_shm);
356 +
357 + ebpf_obsolete_shm_services(em);
358 +
359 + ebpf_cgroup_target_t *ect;
360 + for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
361 + if (ect->systemd)
362 + continue;
363 +
364 + ebpf_obsolete_specific_shm_charts(ect->name, em->update_every);
365 + }
366 + pthread_mutex_unlock(&mutex_cgroup_shm);
367 +}
368 +
369 +/**
370 + * Obsolette apps charts
371 + *
372 + * Obsolete apps charts.
373 + *
374 + * @param em a pointer to the structure with the default values.
375 + */
376 +void ebpf_obsolete_shm_apps_charts(struct ebpf_module *em)
377 +{
378 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
379 + NETDATA_SHMGET_CHART,
380 + "Calls to syscall <code>shmget(2)</code>.",
381 + EBPF_COMMON_DIMENSION_CALL,
382 + NETDATA_APPS_IPC_SHM_GROUP,
383 + NETDATA_EBPF_CHART_TYPE_STACKED,
384 + NULL,
385 + 20191,
386 + em->update_every);
387 +
388 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
389 + NETDATA_SHMAT_CHART,
390 + "Calls to syscall <code>shmat(2)</code>.",
391 + EBPF_COMMON_DIMENSION_CALL,
392 + NETDATA_APPS_IPC_SHM_GROUP,
393 + NETDATA_EBPF_CHART_TYPE_STACKED,
394 + NULL,
395 + 20192,
396 + em->update_every);
397 +
398 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
399 + NETDATA_SHMDT_CHART,
400 + "Calls to syscall <code>shmdt(2)</code>.",
401 + EBPF_COMMON_DIMENSION_CALL,
402 + NETDATA_APPS_IPC_SHM_GROUP,
403 + NETDATA_EBPF_CHART_TYPE_STACKED,
404 + NULL,
405 + 20193,
406 + em->update_every);
407 +
408 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
409 + NETDATA_SHMCTL_CHART,
410 + "Calls to syscall <code>shmctl(2)</code>.",
411 + EBPF_COMMON_DIMENSION_CALL,
412 + NETDATA_APPS_IPC_SHM_GROUP,
413 + NETDATA_EBPF_CHART_TYPE_STACKED,
414 + NULL,
415 + 20194,
416 + em->update_every);
417 +}
418 +
419 +/**
420 + * Obsolete global
421 + *
422 + * Obsolete global charts created by thread.
423 + *
424 + * @param em a pointer to `struct ebpf_module`
425 + */
426 +static void ebpf_obsolete_shm_global(ebpf_module_t *em)
427 +{
428 + ebpf_write_chart_obsolete(NETDATA_EBPF_SYSTEM_GROUP,
429 + NETDATA_SHM_GLOBAL_CHART,
430 + "Calls to shared memory system calls",
431 + EBPF_COMMON_DIMENSION_CALL,
432 + NETDATA_SYSTEM_IPC_SHM_SUBMENU,
433 + NETDATA_EBPF_CHART_TYPE_LINE,
434 + NULL,
435 + NETDATA_CHART_PRIO_SYSTEM_IPC_SHARED_MEM_CALLS,
436 + em->update_every);
437 +}
438 +
439 /**
440 * SHM Exit
441 *
@@ -299,16 +447,46 @@ static void ebpf_shm_exit(void *ptr)
447 {
448 ebpf_module_t *em = (ebpf_module_t *)ptr;
449
450 + if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
451 + pthread_mutex_lock(&lock);
452 + if (em->cgroup_charts) {
453 + ebpf_obsolete_shm_cgroup_charts(em);
454 + fflush(stdout);
455 + }
456 +
457 + if (em->apps_charts & NETDATA_EBPF_APPS_FLAG_CHART_CREATED) {
458 + ebpf_obsolete_shm_apps_charts(em);
459 + }
460 +
461 + ebpf_obsolete_shm_global(em);
462 +
463 +#ifdef NETDATA_DEV_MODE
464 + if (ebpf_aral_shm_pid)
465 + ebpf_statistic_obsolete_aral_chart(em, shm_disable_priority);
466 +#endif
467 +
468 + fflush(stdout);
469 + pthread_mutex_unlock(&lock);
470 + }
471 +
472 + ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_REMOVE);
473 +
474 #ifdef LIBBPF_MAJOR_VERSION
303 - if (shm_bpf_obj)
475 + if (shm_bpf_obj) {
476 shm_bpf__destroy(shm_bpf_obj);
477 + shm_bpf_obj = NULL;
478 + }
479 #endif
480
307 - if (em->objects)
481 + if (em->objects) {
482 ebpf_unload_legacy_code(em->objects, em->probe_links);
483 + em->objects = NULL;
484 + em->probe_links = NULL;
485 + }
486
487 pthread_mutex_lock(&ebpf_exit_cleanup);
488 em->enabled = NETDATA_THREAD_EBPF_STOPPED;
489 + ebpf_update_stats(&plugin_statistics, em);
490 pthread_mutex_unlock(&ebpf_exit_cleanup);
491 }
492
@@ -859,7 +1037,9 @@ static void shm_collector(ebpf_module_t *em)
1037 heartbeat_init(&hb);
1038 int counter = update_every - 1;
1039 int maps_per_core = em->maps_per_core;
862 - while (!ebpf_exit_plugin) {
1040 + uint32_t running_time = 0;
1041 + uint32_t lifetime = em->lifetime;
1042 + while (!ebpf_exit_plugin && running_time < lifetime) {
1043 (void)heartbeat_next(&hb, USEC_PER_SEC);
1044 if (ebpf_exit_plugin || ++counter != update_every)
1045 continue;
@@ -895,6 +1075,15 @@ static void shm_collector(ebpf_module_t *em)
1075
1076 pthread_mutex_unlock(&lock);
1077 pthread_mutex_unlock(&collect_data_mutex);
1078 +
1079 + pthread_mutex_lock(&ebpf_exit_cleanup);
1080 + if (running_time && !em->running_time)
1081 + running_time = update_every;
1082 + else
1083 + running_time += update_every;
1084 +
1085 + em->running_time = running_time;
1086 + pthread_mutex_unlock(&ebpf_exit_cleanup);
1087 }
1088 }
1089
@@ -1084,10 +1273,10 @@ void *ebpf_shm_thread(void *ptr)
1273 pthread_mutex_lock(&lock);
1274 ebpf_create_shm_charts(em->update_every);
1275 ebpf_update_stats(&plugin_statistics, em);
1087 - ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps);
1276 + ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_ADD);
1277 #ifdef NETDATA_DEV_MODE
1278 if (ebpf_aral_shm_pid)
1090 - ebpf_statistic_create_aral_chart(NETDATA_EBPF_SHM_ARAL_NAME, em);
1279 + shm_disable_priority = ebpf_statistic_create_aral_chart(NETDATA_EBPF_SHM_ARAL_NAME, em);
1280 #endif
1281
1282 pthread_mutex_unlock(&lock);
collectors/ebpf.plugin/ebpf_shm.h
+2 -1
@@ -3,8 +3,9 @@
3 #ifndef NETDATA_EBPF_SHM_H
4 #define NETDATA_EBPF_SHM_H 1
5
6 -// Module name
6 +// Module name & description
7 #define NETDATA_EBPF_MODULE_NAME_SHM "shm"
8 +#define NETDATA_EBPF_SHM_MODULE_DESC "Show calls to syscalls shmget(2), shmat(2), shmdt(2) and shmctl(2). This thread is integrated with apps and cgroup."
9
10 // charts
11 #define NETDATA_SHM_GLOBAL_CHART "shared_memory_calls"
collectors/ebpf.plugin/ebpf_socket.c
+25 -4
@@ -130,6 +130,10 @@ struct netdata_static_thread socket_threads = {
130 .start_routine = NULL
131 };
132
133 +#ifdef NETDATA_DEV_MODE
134 +int socket_disable_priority;
135 +#endif
136 +
137 #ifdef LIBBPF_MAJOR_VERSION
138 /**
139 * Disable Probe
@@ -646,6 +650,8 @@ static void ebpf_socket_free(ebpf_module_t *em )
650
651 pthread_mutex_lock(&ebpf_exit_cleanup);
652 em->enabled = NETDATA_THREAD_EBPF_STOPPED;
653 + ebpf_update_stats(&plugin_statistics, em);
654 + ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_REMOVE);
655 pthread_mutex_unlock(&ebpf_exit_cleanup);
656 }
657
@@ -1217,6 +1223,8 @@ static void ebpf_create_global_charts(ebpf_module_t *em)
1223 &socket_publish_aggregated[NETDATA_IDX_UDP_RECVBUF],
1224 2, em->update_every, NETDATA_EBPF_MODULE_NAME_SOCKET);
1225 }
1226 +
1227 + fflush(stdout);
1228 }
1229
1230 /**
@@ -2177,7 +2185,9 @@ void *ebpf_socket_read_hash(void *ptr)
2185 int fd_ipv6 = socket_maps[NETDATA_SOCKET_TABLE_IPV6].map_fd;
2186 int maps_per_core = em->maps_per_core;
2187 // This thread is cancelled from another thread
2180 - for (;;) {
2188 + uint32_t running_time;
2189 + uint32_t lifetime = em->lifetime;
2190 + for (running_time = 0;!ebpf_exit_plugin && running_time < lifetime; running_time++) {
2191 (void)heartbeat_next(&hb, USEC_PER_SEC);
2192 if (ebpf_exit_plugin)
2193 break;
@@ -2918,7 +2928,9 @@ static void socket_collector(ebpf_module_t *em)
2928 int update_every = em->update_every;
2929 int maps_per_core = em->maps_per_core;
2930 int counter = update_every - 1;
2921 - while (!ebpf_exit_plugin) {
2931 + uint32_t running_time = 0;
2932 + uint32_t lifetime = em->lifetime;
2933 + while (!ebpf_exit_plugin && running_time < lifetime) {
2934 (void)heartbeat_next(&hb, USEC_PER_SEC);
2935 if (ebpf_exit_plugin || ++counter != update_every)
2936 continue;
@@ -2973,6 +2985,15 @@ static void socket_collector(ebpf_module_t *em)
2985 }
2986 pthread_mutex_unlock(&lock);
2987 pthread_mutex_unlock(&collect_data_mutex);
2988 +
2989 + pthread_mutex_lock(&ebpf_exit_cleanup);
2990 + if (running_time && !em->running_time)
2991 + running_time = update_every;
2992 + else
2993 + running_time += update_every;
2994 +
2995 + em->running_time = running_time;
2996 + pthread_mutex_unlock(&ebpf_exit_cleanup);
2997 }
2998 }
2999
@@ -4015,11 +4036,11 @@ void *ebpf_socket_thread(void *ptr)
4036 ebpf_create_global_charts(em);
4037
4038 ebpf_update_stats(&plugin_statistics, em);
4018 - ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps);
4039 + ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_ADD);
4040
4041 #ifdef NETDATA_DEV_MODE
4042 if (ebpf_aral_socket_pid)
4022 - ebpf_statistic_create_aral_chart(NETDATA_EBPF_SOCKET_ARAL_NAME, em);
4043 + socket_disable_priority = ebpf_statistic_create_aral_chart(NETDATA_EBPF_SOCKET_ARAL_NAME, em);
4044 #endif
4045
4046 pthread_mutex_unlock(&lock);
collectors/ebpf.plugin/ebpf_socket.h
+2 -1
@@ -4,8 +4,9 @@
4 #include <stdint.h>
5 #include "libnetdata/avl/avl.h"
6
7 -// Module name
7 +// Module name & description
8 #define NETDATA_EBPF_MODULE_NAME_SOCKET "socket"
9 +#define NETDATA_EBPF_SOCKET_MODULE_DESC "Monitors TCP and UDP bandwidth. This thread is integrated with apps and cgroup."
10
11 // Vector indexes
12 #define NETDATA_UDP_START 3
collectors/ebpf.plugin/ebpf_softirq.c
+50 -3
@@ -60,6 +60,26 @@ static softirq_val_t softirq_vals[] = {
60 // tmp store for soft IRQ values we get from a per-CPU eBPF map.
61 static softirq_ebpf_val_t *softirq_ebpf_vals = NULL;
62
63 +/**
64 + * Obsolete global
65 + *
66 + * Obsolete global charts created by thread.
67 + *
68 + * @param em a pointer to `struct ebpf_module`
69 + */
70 +static void ebpf_obsolete_softirq_global(ebpf_module_t *em)
71 +{
72 + ebpf_write_chart_obsolete(NETDATA_EBPF_SYSTEM_GROUP,
73 + "softirq_latency",
74 + "Software IRQ latency",
75 + EBPF_COMMON_DIMENSION_MILLISECONDS,
76 + "softirqs",
77 + NETDATA_EBPF_CHART_TYPE_STACKED,
78 + NULL,
79 + NETDATA_CHART_PRIO_SYSTEM_SOFTIRQS+1,
80 + em->update_every);
81 +}
82 +
83 /**
84 * Cleanup
85 *
@@ -71,16 +91,32 @@ static void softirq_cleanup(void *ptr)
91 {
92 ebpf_module_t *em = (ebpf_module_t *)ptr;
93
74 - if (em->objects)
94 + if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
95 + pthread_mutex_lock(&lock);
96 +
97 + ebpf_obsolete_softirq_global(em);
98 +
99 + pthread_mutex_unlock(&lock);
100 + fflush(stdout);
101 + }
102 +
103 + ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_REMOVE);
104 +
105 + if (em->objects) {
106 ebpf_unload_legacy_code(em->objects, em->probe_links);
107 + em->objects = NULL;
108 + em->probe_links = NULL;
109 + }
110
111 for (int i = 0; softirq_tracepoints[i].class != NULL; i++) {
112 ebpf_disable_tracepoint(&softirq_tracepoints[i]);
113 }
114 freez(softirq_ebpf_vals);
115 + softirq_ebpf_vals = NULL;
116
117 pthread_mutex_lock(&ebpf_exit_cleanup);
118 em->enabled = NETDATA_THREAD_EBPF_STOPPED;
119 + ebpf_update_stats(&plugin_statistics, em);
120 pthread_mutex_unlock(&ebpf_exit_cleanup);
121 }
122
@@ -170,7 +206,7 @@ static void softirq_collector(ebpf_module_t *em)
206 softirq_create_charts(em->update_every);
207 softirq_create_dims();
208 ebpf_update_stats(&plugin_statistics, em);
173 - ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps);
209 + ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_ADD);
210 pthread_mutex_unlock(&lock);
211
212 // loop and read from published data until ebpf plugin is closed.
@@ -180,7 +216,9 @@ static void softirq_collector(ebpf_module_t *em)
216 int counter = update_every - 1;
217 int maps_per_core = em->maps_per_core;
218 //This will be cancelled by its parent
183 - while (!ebpf_exit_plugin) {
219 + uint32_t running_time = 0;
220 + uint32_t lifetime = em->lifetime;
221 + while (!ebpf_exit_plugin && running_time < lifetime) {
222 (void)heartbeat_next(&hb, USEC_PER_SEC);
223 if (ebpf_exit_plugin || ++counter != update_every)
224 continue;
@@ -195,6 +233,15 @@ static void softirq_collector(ebpf_module_t *em)
233 write_end_chart();
234
235 pthread_mutex_unlock(&lock);
236 +
237 + pthread_mutex_lock(&ebpf_exit_cleanup);
238 + if (running_time && !em->running_time)
239 + running_time = update_every;
240 + else
241 + running_time += update_every;
242 +
243 + em->running_time = running_time;
244 + pthread_mutex_unlock(&ebpf_exit_cleanup);
245 }
246 }
247
collectors/ebpf.plugin/ebpf_softirq.h
+3
@@ -3,6 +3,9 @@
3 #ifndef NETDATA_EBPF_SOFTIRQ_H
4 #define NETDATA_EBPF_SOFTIRQ_H 1
5
6 +// Module observation
7 +#define NETDATA_EBPF_SOFTIRQ_MODULE_DESC "Show time spent servicing individual software interrupt requests (soft IRQs)."
8 +
9 /*****************************************************************
10 * copied from kernel-collectors repo, with modifications needed
11 * for inclusion here.
collectors/ebpf.plugin/ebpf_swap.c
+145 -4
@@ -229,6 +229,109 @@ static inline int ebpf_swap_load_and_attach(struct swap_bpf *obj, ebpf_module_t
229 *
230 *****************************************************************/
231
232 +static void ebpf_obsolete_specific_swap_charts(char *type, int update_every);
233 +
234 +/**
235 + * Obsolete services
236 + *
237 + * Obsolete all service charts created
238 + *
239 + * @param em a pointer to `struct ebpf_module`
240 + */
241 +static void ebpf_obsolete_swap_services(ebpf_module_t *em)
242 +{
243 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
244 + NETDATA_MEM_SWAP_READ_CHART,
245 + "Calls to function <code>swap_readpage</code>.",
246 + EBPF_COMMON_DIMENSION_CALL,
247 + NETDATA_SYSTEM_CGROUP_SWAP_SUBMENU,
248 + NETDATA_EBPF_CHART_TYPE_LINE,
249 + NETDATA_CGROUP_SWAP_READ_CONTEXT,
250 + NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5100,
251 + em->update_every);
252 +
253 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
254 + NETDATA_MEM_SWAP_WRITE_CHART,
255 + "Calls to function <code>swap_writepage</code>.",
256 + EBPF_COMMON_DIMENSION_CALL,
257 + NETDATA_SYSTEM_CGROUP_SWAP_SUBMENU,
258 + NETDATA_EBPF_CHART_TYPE_LINE,
259 + NETDATA_CGROUP_SWAP_WRITE_CONTEXT,
260 + NETDATA_CHART_PRIO_CGROUPS_CONTAINERS + 5101,
261 + em->update_every);
262 +}
263 +
264 +/**
265 + * Obsolete cgroup chart
266 + *
267 + * Send obsolete for all charts created before to close.
268 + *
269 + * @param em a pointer to `struct ebpf_module`
270 + */
271 +static inline void ebpf_obsolete_swap_cgroup_charts(ebpf_module_t *em) {
272 + pthread_mutex_lock(&mutex_cgroup_shm);
273 +
274 + ebpf_obsolete_swap_services(em);
275 +
276 + ebpf_cgroup_target_t *ect;
277 + for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
278 + if (ect->systemd)
279 + continue;
280 +
281 + ebpf_obsolete_specific_swap_charts(ect->name, em->update_every);
282 + }
283 + pthread_mutex_unlock(&mutex_cgroup_shm);
284 +}
285 +
286 +/**
287 + * Obsolette apps charts
288 + *
289 + * Obsolete apps charts.
290 + *
291 + * @param em a pointer to the structure with the default values.
292 + */
293 +void ebpf_obsolete_swap_apps_charts(struct ebpf_module *em)
294 +{
295 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
296 + NETDATA_MEM_SWAP_READ_CHART,
297 + "Calls to function <code>swap_readpage</code>.",
298 + EBPF_COMMON_DIMENSION_CALL,
299 + NETDATA_SWAP_SUBMENU,
300 + NETDATA_EBPF_CHART_TYPE_STACKED,
301 + NULL,
302 + 20191,
303 + em->update_every);
304 +
305 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
306 + NETDATA_MEM_SWAP_WRITE_CHART,
307 + "Calls to function <code>swap_writepage</code>.",
308 + EBPF_COMMON_DIMENSION_CALL,
309 + NETDATA_SWAP_SUBMENU,
310 + NETDATA_EBPF_CHART_TYPE_STACKED,
311 + NULL,
312 + 20192,
313 + em->update_every);
314 +}
315 +
316 +/**
317 + * Obsolete global
318 + *
319 + * Obsolete global charts created by thread.
320 + *
321 + * @param em a pointer to `struct ebpf_module`
322 + */
323 +static void ebpf_obsolete_swap_global(ebpf_module_t *em)
324 +{
325 + ebpf_write_chart_obsolete(NETDATA_EBPF_SYSTEM_GROUP,
326 + NETDATA_MEM_SWAP_CHART,
327 + "Calls to access swap memory",
328 + EBPF_COMMON_DIMENSION_CALL, NETDATA_SYSTEM_SWAP_SUBMENU,
329 + NETDATA_EBPF_CHART_TYPE_LINE,
330 + NULL,
331 + NETDATA_CHART_PRIO_SYSTEM_SWAP_CALLS,
332 + em->update_every);
333 +}
334 +
335 /**
336 * Swap exit
337 *
@@ -240,15 +343,40 @@ static void ebpf_swap_exit(void *ptr)
343 {
344 ebpf_module_t *em = (ebpf_module_t *)ptr;
345
346 + if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
347 + pthread_mutex_lock(&lock);
348 + if (em->cgroup_charts) {
349 + ebpf_obsolete_swap_cgroup_charts(em);
350 + fflush(stdout);
351 + }
352 +
353 + if (em->apps_charts & NETDATA_EBPF_APPS_FLAG_CHART_CREATED) {
354 + ebpf_obsolete_swap_apps_charts(em);
355 + }
356 +
357 + ebpf_obsolete_swap_global(em);
358 +
359 + fflush(stdout);
360 + pthread_mutex_unlock(&lock);
361 + }
362 +
363 + ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_REMOVE);
364 +
365 #ifdef LIBBPF_MAJOR_VERSION
244 - if (bpf_obj)
366 + if (bpf_obj) {
367 swap_bpf__destroy(bpf_obj);
368 + bpf_obj = NULL;
369 + }
370 #endif
247 - if (em->objects)
371 + if (em->objects) {
372 ebpf_unload_legacy_code(em->objects, em->probe_links);
373 + em->objects = NULL;
374 + em->probe_links = NULL;
375 + }
376
377 pthread_mutex_lock(&ebpf_exit_cleanup);
378 em->enabled = NETDATA_THREAD_EBPF_STOPPED;
379 + ebpf_update_stats(&plugin_statistics, em);
380 pthread_mutex_unlock(&ebpf_exit_cleanup);
381 }
382
@@ -674,7 +802,9 @@ static void swap_collector(ebpf_module_t *em)
802 heartbeat_init(&hb);
803 int counter = update_every - 1;
804 int maps_per_core = em->maps_per_core;
677 - while (!ebpf_exit_plugin) {
805 + uint32_t running_time = 0;
806 + uint32_t lifetime = em->lifetime;
807 + while (!ebpf_exit_plugin && running_time < lifetime) {
808 (void)heartbeat_next(&hb, USEC_PER_SEC);
809 if (ebpf_exit_plugin || ++counter != update_every)
810 continue;
@@ -701,6 +831,15 @@ static void swap_collector(ebpf_module_t *em)
831
832 pthread_mutex_unlock(&lock);
833 pthread_mutex_unlock(&collect_data_mutex);
834 +
835 + pthread_mutex_lock(&ebpf_exit_cleanup);
836 + if (running_time && !em->running_time)
837 + running_time = update_every;
838 + else
839 + running_time += update_every;
840 +
841 + em->running_time = running_time;
842 + pthread_mutex_unlock(&ebpf_exit_cleanup);
843 }
844 }
845
@@ -784,6 +923,8 @@ static void ebpf_create_swap_charts(int update_every)
923 ebpf_create_global_dimension,
924 swap_publish_aggregated, NETDATA_SWAP_END,
925 update_every, NETDATA_EBPF_MODULE_NAME_SWAP);
926 +
927 + fflush(stdout);
928 }
929
930 /*
@@ -857,7 +998,7 @@ void *ebpf_swap_thread(void *ptr)
998 pthread_mutex_lock(&lock);
999 ebpf_create_swap_charts(em->update_every);
1000 ebpf_update_stats(&plugin_statistics, em);
860 - ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps);
1001 + ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_ADD);
1002 pthread_mutex_unlock(&lock);
1003
1004 swap_collector(em);
collectors/ebpf.plugin/ebpf_swap.h
+2 -1
@@ -3,8 +3,9 @@
3 #ifndef NETDATA_EBPF_SWAP_H
4 #define NETDATA_EBPF_SWAP_H 1
5
6 -// Module name
6 +// Module name & description
7 #define NETDATA_EBPF_MODULE_NAME_SWAP "swap"
8 +#define NETDATA_EBPF_SWAP_MODULE_DESC "Monitor swap space usage. This thread is integrated with apps and cgroup."
9
10 #define NETDATA_SWAP_SLEEP_MS 850000ULL
11
collectors/ebpf.plugin/ebpf_sync.c
+97 -15
@@ -248,7 +248,6 @@ static inline int ebpf_sync_load_and_attach(struct sync_bpf *obj, ebpf_module_t
248 *
249 *****************************************************************/
250
251 -#ifdef LIBBPF_MAJOR_VERSION
251 /**
252 * Cleanup Objects
253 *
@@ -259,28 +258,86 @@ void ebpf_sync_cleanup_objects()
258 int i;
259 for (i = 0; local_syscalls[i].syscall; i++) {
260 ebpf_sync_syscalls_t *w = &local_syscalls[i];
262 - if (w->sync_obj)
261 +#ifdef LIBBPF_MAJOR_VERSION
262 + if (w->sync_obj) {
263 sync_bpf__destroy(w->sync_obj);
264 + w->sync_obj = NULL;
265 + }
266 +#endif
267 + if (w->probe_links) {
268 + ebpf_unload_legacy_code(w->objects, w->probe_links);
269 + w->objects = NULL;
270 + w->probe_links = NULL;
271 + }
272 }
273 }
266 -#endif
274 +
275 +/*
276 + static void ebpf_create_sync_chart(char *id,
277 + char *title,
278 + int order,
279 + int idx,
280 + int end,
281 + int update_every)
282 + {
283 + ebpf_write_chart_cmd(NETDATA_EBPF_MEMORY_GROUP, id, title, EBPF_COMMON_DIMENSION_CALL,
284 + NETDATA_EBPF_SYNC_SUBMENU, NETDATA_EBPF_CHART_TYPE_LINE, NULL, order,
285 + update_every,
286 + NETDATA_EBPF_MODULE_NAME_SYNC);
287 + */
288
289 /**
269 - * Sync Free
290 + * Obsolete global
291 *
271 - * Cleanup variables after child threads to stop
292 + * Obsolete global charts created by thread.
293 *
273 - * @param ptr thread data.
294 + * @param em a pointer to `struct ebpf_module`
295 */
275 -static void ebpf_sync_free(ebpf_module_t *em)
296 +static void ebpf_obsolete_sync_global(ebpf_module_t *em)
297 {
277 -#ifdef LIBBPF_MAJOR_VERSION
278 - ebpf_sync_cleanup_objects();
279 -#endif
298 + if (local_syscalls[NETDATA_SYNC_FSYNC_IDX].enabled && local_syscalls[NETDATA_SYNC_FDATASYNC_IDX].enabled)
299 + ebpf_write_chart_obsolete(NETDATA_EBPF_MEMORY_GROUP,
300 + NETDATA_EBPF_FILE_SYNC_CHART,
301 + "Monitor calls for <code>fsync(2)</code> and <code>fdatasync(2)</code>.",
302 + EBPF_COMMON_DIMENSION_CALL,
303 + NETDATA_EBPF_SYNC_SUBMENU,
304 + NETDATA_EBPF_CHART_TYPE_LINE,
305 + NULL,
306 + 21300,
307 + em->update_every);
308
281 - pthread_mutex_lock(&ebpf_exit_cleanup);
282 - em->enabled = NETDATA_THREAD_EBPF_STOPPED;
283 - pthread_mutex_unlock(&ebpf_exit_cleanup);
309 + if (local_syscalls[NETDATA_SYNC_MSYNC_IDX].enabled)
310 + ebpf_write_chart_obsolete(NETDATA_EBPF_MEMORY_GROUP,
311 + NETDATA_EBPF_MSYNC_CHART,
312 + "Monitor calls for <code>msync(2)</code>.",
313 + EBPF_COMMON_DIMENSION_CALL,
314 + NETDATA_EBPF_SYNC_SUBMENU,
315 + NETDATA_EBPF_CHART_TYPE_LINE,
316 + NULL,
317 + 21301,
318 + em->update_every);
319 +
320 + if (local_syscalls[NETDATA_SYNC_SYNC_IDX].enabled && local_syscalls[NETDATA_SYNC_SYNCFS_IDX].enabled)
321 + ebpf_write_chart_obsolete(NETDATA_EBPF_MEMORY_GROUP,
322 + NETDATA_EBPF_SYNC_CHART,
323 + "Monitor calls for <code>sync(2)</code> and <code>syncfs(2)</code>.",
324 + EBPF_COMMON_DIMENSION_CALL,
325 + NETDATA_EBPF_SYNC_SUBMENU,
326 + NETDATA_EBPF_CHART_TYPE_LINE,
327 + NULL,
328 + 21302,
329 + em->update_every);
330 +
331 + if (local_syscalls[NETDATA_SYNC_SYNC_FILE_RANGE_IDX].enabled)
332 + ebpf_write_chart_obsolete(NETDATA_EBPF_MEMORY_GROUP,
333 + NETDATA_EBPF_FILE_SEGMENT_CHART,
334 + "Monitor calls for <code>sync_file_range(2)</code>.",
335 + EBPF_COMMON_DIMENSION_CALL,
336 + NETDATA_EBPF_SYNC_SUBMENU,
337 + NETDATA_EBPF_CHART_TYPE_LINE,
338 + NULL,
339 + 21303,
340 + em->update_every);
341 }
342
343 /**
@@ -293,7 +350,19 @@ static void ebpf_sync_free(ebpf_module_t *em)
350 static void ebpf_sync_exit(void *ptr)
351 {
352 ebpf_module_t *em = (ebpf_module_t *)ptr;
296 - ebpf_sync_free(em);
353 +
354 + if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
355 + pthread_mutex_lock(&lock);
356 + ebpf_obsolete_sync_global(em);
357 + pthread_mutex_unlock(&lock);
358 + }
359 +
360 + ebpf_sync_cleanup_objects();
361 +
362 + pthread_mutex_lock(&ebpf_exit_cleanup);
363 + em->enabled = NETDATA_THREAD_EBPF_STOPPED;
364 + ebpf_update_stats(&plugin_statistics, em);
365 + pthread_mutex_unlock(&ebpf_exit_cleanup);
366 }
367
368 /*****************************************************************
@@ -489,7 +558,9 @@ static void sync_collector(ebpf_module_t *em)
558 int update_every = em->update_every;
559 int counter = update_every - 1;
560 int maps_per_core = em->maps_per_core;
492 - while (!ebpf_exit_plugin) {
561 + uint32_t running_time = 0;
562 + uint32_t lifetime = em->lifetime;
563 + while (!ebpf_exit_plugin && running_time < lifetime) {
564 (void)heartbeat_next(&hb, USEC_PER_SEC);
565 if (ebpf_exit_plugin || ++counter != update_every)
566 continue;
@@ -501,6 +572,15 @@ static void sync_collector(ebpf_module_t *em)
572 sync_send_data();
573
574 pthread_mutex_unlock(&lock);
575 +
576 + pthread_mutex_lock(&ebpf_exit_cleanup);
577 + if (running_time && !em->running_time)
578 + running_time = update_every;
579 + else
580 + running_time += update_every;
581 +
582 + em->running_time = running_time;
583 + pthread_mutex_unlock(&ebpf_exit_cleanup);
584 }
585 }
586
@@ -574,6 +654,8 @@ static void ebpf_create_sync_charts(int update_every)
654 ebpf_create_sync_chart(NETDATA_EBPF_FILE_SEGMENT_CHART,
655 "Monitor calls for <code>sync_file_range(2)</code>.", 21303,
656 NETDATA_SYNC_SYNC_FILE_RANGE_IDX, NETDATA_SYNC_SYNC_FILE_RANGE_IDX, update_every);
657 +
658 + fflush(stdout);
659 }
660
661 /**
collectors/ebpf.plugin/ebpf_sync.h
+2 -1
@@ -7,8 +7,9 @@
7 #include "includes/sync.skel.h"
8 #endif
9
10 -// Module name
10 +// Module name & description
11 #define NETDATA_EBPF_MODULE_NAME_SYNC "sync"
12 +#define NETDATA_EBPF_SYNC_MODULE_DESC "Monitor calls to syscalls sync(2), fsync(2), fdatasync(2), syncfs(2), msync(2), and sync_file_range(2)."
13
14 // charts
15 #define NETDATA_EBPF_SYNC_CHART "sync"
collectors/ebpf.plugin/ebpf_vfs.c
+493 -5
@@ -60,6 +60,10 @@ netdata_ebpf_targets_t vfs_targets[] = { {.name = "vfs_write", .mode = EBPF_LOAD
60 {.name = "release_task", .mode = EBPF_LOAD_TRAMPOLINE},
61 {.name = NULL, .mode = EBPF_LOAD_TRAMPOLINE}};
62
63 +#ifdef NETDATA_DEV_MODE
64 +int vfs_disable_priority;
65 +#endif
66 +
67 #ifdef LIBBPF_MAJOR_VERSION
68 /**
69 * Disable probe
@@ -403,6 +407,447 @@ static inline int ebpf_vfs_load_and_attach(struct vfs_bpf *obj, ebpf_module_t *e
407 *
408 *****************************************************************/
409
410 +static void ebpf_obsolete_specific_vfs_charts(char *type, ebpf_module_t *em);
411 +
412 +/**
413 + * Obsolete services
414 + *
415 + * Obsolete all service charts created
416 + *
417 + * @param em a pointer to `struct ebpf_module`
418 + */
419 +static void ebpf_obsolete_vfs_services(ebpf_module_t *em)
420 +{
421 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
422 + NETDATA_SYSCALL_APPS_FILE_DELETED,
423 + "Files deleted",
424 + EBPF_COMMON_DIMENSION_CALL,
425 + NETDATA_VFS_CGROUP_GROUP,
426 + NETDATA_EBPF_CHART_TYPE_STACKED,
427 + NULL,
428 + 20065,
429 + em->update_every);
430 +
431 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
432 + NETDATA_SYSCALL_APPS_VFS_WRITE_CALLS,
433 + "Write to disk",
434 + EBPF_COMMON_DIMENSION_CALL,
435 + NETDATA_VFS_CGROUP_GROUP,
436 + NETDATA_EBPF_CHART_TYPE_STACKED,
437 + NULL,
438 + 20066,
439 + em->update_every);
440 +
441 + if (em->mode < MODE_ENTRY) {
442 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
443 + NETDATA_SYSCALL_APPS_VFS_WRITE_CALLS_ERROR,
444 + "Fails to write",
445 + EBPF_COMMON_DIMENSION_CALL,
446 + NETDATA_VFS_CGROUP_GROUP,
447 + NETDATA_EBPF_CHART_TYPE_STACKED,
448 + NULL,
449 + 20067,
450 + em->update_every);
451 + }
452 +
453 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
454 + NETDATA_SYSCALL_APPS_VFS_READ_CALLS,
455 + "Read from disk",
456 + EBPF_COMMON_DIMENSION_CALL,
457 + NETDATA_VFS_CGROUP_GROUP,
458 + NETDATA_EBPF_CHART_TYPE_STACKED,
459 + NULL,
460 + 20068,
461 + em->update_every);
462 +
463 + if (em->mode < MODE_ENTRY) {
464 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
465 + NETDATA_SYSCALL_APPS_VFS_READ_CALLS_ERROR,
466 + "Fails to read",
467 + EBPF_COMMON_DIMENSION_CALL,
468 + NETDATA_VFS_CGROUP_GROUP,
469 + NETDATA_EBPF_CHART_TYPE_STACKED,
470 + NULL,
471 + 20069,
472 + em->update_every);
473 + }
474 +
475 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
476 + NETDATA_SYSCALL_APPS_VFS_WRITE_BYTES,
477 + "Bytes written on disk",
478 + EBPF_COMMON_DIMENSION_BYTES,
479 + NETDATA_VFS_CGROUP_GROUP,
480 + NETDATA_EBPF_CHART_TYPE_STACKED,
481 + NULL,
482 + 20070,
483 + em->update_every);
484 +
485 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
486 + NETDATA_SYSCALL_APPS_VFS_READ_BYTES,
487 + "Bytes read from disk",
488 + EBPF_COMMON_DIMENSION_BYTES,
489 + NETDATA_VFS_CGROUP_GROUP,
490 + NETDATA_EBPF_CHART_TYPE_STACKED,
491 + NULL,
492 + 20071,
493 + em->update_every);
494 +
495 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
496 + NETDATA_SYSCALL_APPS_VFS_FSYNC,
497 + "Calls to <code>vfs_fsync</code>",
498 + EBPF_COMMON_DIMENSION_CALL,
499 + NETDATA_VFS_CGROUP_GROUP,
500 + NETDATA_EBPF_CHART_TYPE_STACKED,
501 + NULL,
502 + 20072,
503 + em->update_every);
504 +
505 + if (em->mode < MODE_ENTRY) {
506 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
507 + NETDATA_SYSCALL_APPS_VFS_FSYNC_CALLS_ERROR,
508 + "Sync error",
509 + EBPF_COMMON_DIMENSION_CALL,
510 + NETDATA_VFS_CGROUP_GROUP,
511 + NETDATA_EBPF_CHART_TYPE_STACKED,
512 + NULL,
513 + 20073,
514 + em->update_every);
515 + }
516 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
517 + NETDATA_SYSCALL_APPS_VFS_OPEN,
518 + "Calls to <code>vfs_open</code>",
519 + EBPF_COMMON_DIMENSION_CALL,
520 + NETDATA_VFS_CGROUP_GROUP,
521 + NETDATA_EBPF_CHART_TYPE_STACKED,
522 + NULL,
523 + 20074,
524 + em->update_every);
525 +
526 + if (em->mode < MODE_ENTRY) {
527 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
528 + NETDATA_SYSCALL_APPS_VFS_OPEN_CALLS_ERROR,
529 + "Open error",
530 + EBPF_COMMON_DIMENSION_CALL,
531 + NETDATA_VFS_CGROUP_GROUP,
532 + NETDATA_EBPF_CHART_TYPE_STACKED,
533 + NULL,
534 + 20075,
535 + em->update_every);
536 + }
537 +
538 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
539 + NETDATA_SYSCALL_APPS_VFS_CREATE,
540 + "Calls to <code>vfs_create</code>",
541 + EBPF_COMMON_DIMENSION_CALL,
542 + NETDATA_VFS_CGROUP_GROUP,
543 + NETDATA_EBPF_CHART_TYPE_STACKED,
544 + NULL,
545 + 20076,
546 + em->update_every);
547 +
548 + if (em->mode < MODE_ENTRY) {
549 + ebpf_write_chart_obsolete(NETDATA_SERVICE_FAMILY,
550 + NETDATA_SYSCALL_APPS_VFS_CREATE_CALLS_ERROR,
551 + "Create error",
552 + EBPF_COMMON_DIMENSION_CALL,
553 + NETDATA_VFS_CGROUP_GROUP,
554 + NETDATA_EBPF_CHART_TYPE_STACKED,
555 + NULL,
556 + 20077,
557 + em->update_every);
558 + }
559 +}
560 +
561 +/**
562 + * Obsolete cgroup chart
563 + *
564 + * Send obsolete for all charts created before to close.
565 + *
566 + * @param em a pointer to `struct ebpf_module`
567 + */
568 +static inline void ebpf_obsolete_vfs_cgroup_charts(ebpf_module_t *em) {
569 + pthread_mutex_lock(&mutex_cgroup_shm);
570 +
571 + ebpf_obsolete_vfs_services(em);
572 +
573 + ebpf_cgroup_target_t *ect;
574 + for (ect = ebpf_cgroup_pids; ect ; ect = ect->next) {
575 + if (ect->systemd)
576 + continue;
577 +
578 + ebpf_obsolete_specific_vfs_charts(ect->name, em);
579 + }
580 + pthread_mutex_unlock(&mutex_cgroup_shm);
581 +}
582 +
583 +/**
584 + * Obsolette apps charts
585 + *
586 + * Obsolete apps charts.
587 + *
588 + * @param em a pointer to the structure with the default values.
589 + */
590 +void ebpf_obsolete_vfs_apps_charts(struct ebpf_module *em)
591 +{
592 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
593 + NETDATA_SYSCALL_APPS_FILE_DELETED,
594 + "Files deleted",
595 + EBPF_COMMON_DIMENSION_CALL,
596 + NETDATA_VFS_GROUP,
597 + NETDATA_EBPF_CHART_TYPE_STACKED,
598 + NULL,
599 + 20065,
600 + em->update_every);
601 +
602 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
603 + NETDATA_SYSCALL_APPS_VFS_WRITE_CALLS,
604 + "Write to disk",
605 + EBPF_COMMON_DIMENSION_CALL,
606 + NETDATA_VFS_GROUP,
607 + NETDATA_EBPF_CHART_TYPE_STACKED,
608 + NULL,
609 + 20066,
610 + em->update_every);
611 +
612 + if (em->mode < MODE_ENTRY) {
613 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
614 + NETDATA_SYSCALL_APPS_VFS_WRITE_CALLS_ERROR,
615 + "Fails to write",
616 + EBPF_COMMON_DIMENSION_CALL,
617 + NETDATA_VFS_GROUP,
618 + NETDATA_EBPF_CHART_TYPE_STACKED,
619 + NULL,
620 + 20067,
621 + em->update_every);
622 + }
623 +
624 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
625 + NETDATA_SYSCALL_APPS_VFS_READ_CALLS,
626 + "Read from disk",
627 + EBPF_COMMON_DIMENSION_CALL,
628 + NETDATA_VFS_GROUP,
629 + NETDATA_EBPF_CHART_TYPE_STACKED,
630 + NULL,
631 + 20068,
632 + em->update_every);
633 +
634 + if (em->mode < MODE_ENTRY) {
635 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
636 + NETDATA_SYSCALL_APPS_VFS_READ_CALLS_ERROR,
637 + "Fails to read",
638 + EBPF_COMMON_DIMENSION_CALL,
639 + NETDATA_VFS_GROUP,
640 + NETDATA_EBPF_CHART_TYPE_STACKED,
641 + NULL,
642 + 20069,
643 + em->update_every);
644 + }
645 +
646 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
647 + NETDATA_SYSCALL_APPS_VFS_WRITE_BYTES,
648 + "Bytes written on disk",
649 + EBPF_COMMON_DIMENSION_BYTES,
650 + NETDATA_VFS_GROUP,
651 + NETDATA_EBPF_CHART_TYPE_STACKED,
652 + NULL,
653 + 20070,
654 + em->update_every);
655 +
656 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
657 + NETDATA_SYSCALL_APPS_VFS_READ_BYTES,
658 + "Bytes read from disk",
659 + EBPF_COMMON_DIMENSION_BYTES,
660 + NETDATA_VFS_GROUP,
661 + NETDATA_EBPF_CHART_TYPE_STACKED,
662 + NULL,
663 + 20071,
664 + em->update_every);
665 +
666 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
667 + NETDATA_SYSCALL_APPS_VFS_FSYNC,
668 + "Calls for <code>vfs_fsync</code>",
669 + EBPF_COMMON_DIMENSION_CALL,
670 + NETDATA_VFS_GROUP,
671 + NETDATA_EBPF_CHART_TYPE_STACKED,
672 + NULL,
673 + 20072,
674 + em->update_every);
675 +
676 + if (em->mode < MODE_ENTRY) {
677 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
678 + NETDATA_SYSCALL_APPS_VFS_FSYNC_CALLS_ERROR,
679 + "Sync error",
680 + EBPF_COMMON_DIMENSION_CALL,
681 + NETDATA_VFS_GROUP,
682 + NETDATA_EBPF_CHART_TYPE_STACKED,
683 + NULL,
684 + 20073,
685 + em->update_every);
686 + }
687 +
688 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
689 + NETDATA_SYSCALL_APPS_VFS_OPEN,
690 + "Calls for <code>vfs_open</code>",
691 + EBPF_COMMON_DIMENSION_CALL,
692 + NETDATA_VFS_GROUP,
693 + NETDATA_EBPF_CHART_TYPE_STACKED,
694 + NULL,
695 + 20074,
696 + em->update_every);
697 +
698 + if (em->mode < MODE_ENTRY) {
699 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
700 + NETDATA_SYSCALL_APPS_VFS_OPEN_CALLS_ERROR,
701 + "Open error",
702 + EBPF_COMMON_DIMENSION_CALL,
703 + NETDATA_VFS_GROUP,
704 + NETDATA_EBPF_CHART_TYPE_STACKED,
705 + NULL,
706 + 20075,
707 + em->update_every);
708 + }
709 +
710 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
711 + NETDATA_SYSCALL_APPS_VFS_CREATE,
712 + "Calls for <code>vfs_create</code>",
713 + EBPF_COMMON_DIMENSION_CALL,
714 + NETDATA_VFS_GROUP,
715 + NETDATA_EBPF_CHART_TYPE_STACKED,
716 + NULL,
717 + 20076,
718 + em->update_every);
719 +
720 + if (em->mode < MODE_ENTRY) {
721 + ebpf_write_chart_obsolete(NETDATA_APPS_FAMILY,
722 + NETDATA_SYSCALL_APPS_VFS_CREATE_CALLS_ERROR,
723 + "Create error",
724 + EBPF_COMMON_DIMENSION_CALL,
725 + NETDATA_VFS_GROUP,
726 + NETDATA_EBPF_CHART_TYPE_STACKED,
727 + NULL,
728 + 20077,
729 + em->update_every);
730 + }
731 +}
732 +
733 +/**
734 + * Obsolete global
735 + *
736 + * Obsolete global charts created by thread.
737 + *
738 + * @param em a pointer to `struct ebpf_module`
739 + */
740 +static void ebpf_obsolete_vfs_global(ebpf_module_t *em)
741 +{
742 + ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY,
743 + NETDATA_VFS_FILE_CLEAN_COUNT,
744 + "Remove files",
745 + EBPF_COMMON_DIMENSION_CALL,
746 + NETDATA_VFS_GROUP,
747 + NETDATA_EBPF_CHART_TYPE_LINE,
748 + NULL,
749 + NETDATA_CHART_PRIO_FILESYSTEM_VFS_CLEAN,
750 + em->update_every);
751 +
752 + ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY,
753 + NETDATA_VFS_FILE_IO_COUNT,
754 + "Calls to IO",
755 + EBPF_COMMON_DIMENSION_CALL,
756 + NETDATA_VFS_GROUP,
757 + NETDATA_EBPF_CHART_TYPE_LINE,
758 + NULL,
759 + NETDATA_CHART_PRIO_FILESYSTEM_VFS_IO_COUNT,
760 + em->update_every);
761 +
762 + ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY,
763 + NETDATA_VFS_IO_FILE_BYTES,
764 + "Bytes written and read",
765 + EBPF_COMMON_DIMENSION_BYTES,
766 + NETDATA_VFS_GROUP,
767 + NETDATA_EBPF_CHART_TYPE_LINE,
768 + NULL,
769 + NETDATA_CHART_PRIO_FILESYSTEM_VFS_IO_BYTES,
770 + em->update_every);
771 +
772 + if (em->mode < MODE_ENTRY) {
773 + ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY,
774 + NETDATA_VFS_FILE_ERR_COUNT,
775 + "Fails to write or read",
776 + EBPF_COMMON_DIMENSION_CALL,
777 + NETDATA_VFS_GROUP,
778 + NETDATA_EBPF_CHART_TYPE_LINE,
779 + NULL,
780 + NETDATA_CHART_PRIO_FILESYSTEM_VFS_IO_EBYTES,
781 + em->update_every);
782 + }
783 +
784 + ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY,
785 + NETDATA_VFS_FSYNC,
786 + "Calls for <code>vfs_fsync</code>",
787 + EBPF_COMMON_DIMENSION_CALL,
788 + NETDATA_VFS_GROUP,
789 + NETDATA_EBPF_CHART_TYPE_LINE,
790 + NULL,
791 + NETDATA_CHART_PRIO_FILESYSTEM_VFS_IO_FSYNC,
792 + em->update_every);
793 +
794 + if (em->mode < MODE_ENTRY) {
795 + ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY,
796 + NETDATA_VFS_FSYNC_ERR,
797 + "Fails to synchronize",
798 + EBPF_COMMON_DIMENSION_CALL,
799 + NETDATA_VFS_GROUP,
800 + NETDATA_EBPF_CHART_TYPE_LINE,
801 + NULL,
802 + NETDATA_CHART_PRIO_FILESYSTEM_VFS_IO_EFSYNC,
803 + em->update_every);
804 + }
805 +
806 + ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY,
807 + NETDATA_VFS_OPEN,
808 + "Calls for <code>vfs_open</code>",
809 + EBPF_COMMON_DIMENSION_CALL,
810 + NETDATA_VFS_GROUP,
811 + NETDATA_EBPF_CHART_TYPE_LINE,
812 + NULL,
813 + NETDATA_CHART_PRIO_FILESYSTEM_VFS_IO_OPEN,
814 + em->update_every);
815 +
816 + if (em->mode < MODE_ENTRY) {
817 + ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY,
818 + NETDATA_VFS_OPEN_ERR,
819 + "Fails to open a file",
820 + EBPF_COMMON_DIMENSION_CALL,
821 + NETDATA_VFS_GROUP,
822 + NETDATA_EBPF_CHART_TYPE_LINE,
823 + NULL,
824 + NETDATA_CHART_PRIO_FILESYSTEM_VFS_IO_EOPEN,
825 + em->update_every);
826 + }
827 +
828 + ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY,
829 + NETDATA_VFS_CREATE,
830 + "Calls for <code>vfs_create</code>",
831 + EBPF_COMMON_DIMENSION_CALL,
832 + NETDATA_VFS_GROUP,
833 + NETDATA_EBPF_CHART_TYPE_LINE,
834 + NULL,
835 + NETDATA_CHART_PRIO_FILESYSTEM_VFS_IO_CREATE,
836 + em->update_every);
837 +
838 + if (em->mode < MODE_ENTRY) {
839 + ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY,
840 + NETDATA_VFS_CREATE_ERR,
841 + "Fails to create a file.",
842 + EBPF_COMMON_DIMENSION_CALL,
843 + NETDATA_VFS_GROUP,
844 + NETDATA_EBPF_CHART_TYPE_LINE,
845 + NULL,
846 + NETDATA_CHART_PRIO_FILESYSTEM_VFS_IO_ECREATE,
847 + em->update_every);
848 + }
849 +}
850 +
851 /**
852 * Exit
853 *
@@ -414,15 +859,45 @@ static void ebpf_vfs_exit(void *ptr)
859 {
860 ebpf_module_t *em = (ebpf_module_t *)ptr;
861
862 + if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
863 + pthread_mutex_lock(&lock);
864 + if (em->cgroup_charts) {
865 + ebpf_obsolete_vfs_cgroup_charts(em);
866 + fflush(stdout);
867 + }
868 +
869 + if (em->apps_charts & NETDATA_EBPF_APPS_FLAG_CHART_CREATED) {
870 + ebpf_obsolete_vfs_apps_charts(em);
871 + }
872 +
873 + ebpf_obsolete_vfs_global(em);
874 +
875 +#ifdef NETDATA_DEV_MODE
876 + if (ebpf_aral_vfs_pid)
877 + ebpf_statistic_obsolete_aral_chart(em, vfs_disable_priority);
878 +#endif
879 +
880 + fflush(stdout);
881 + pthread_mutex_unlock(&lock);
882 + }
883 +
884 + ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_REMOVE);
885 +
886 #ifdef LIBBPF_MAJOR_VERSION
418 - if (vfs_bpf_obj)
887 + if (vfs_bpf_obj) {
888 vfs_bpf__destroy(vfs_bpf_obj);
889 + vfs_bpf_obj = NULL;
890 + }
891 #endif
421 - if (em->objects)
892 + if (em->objects) {
893 ebpf_unload_legacy_code(em->objects, em->probe_links);
894 + em->objects = NULL;
895 + em->probe_links = NULL;
896 + }
897
898 pthread_mutex_lock(&ebpf_exit_cleanup);
899 em->enabled = NETDATA_THREAD_EBPF_STOPPED;
900 + ebpf_update_stats(&plugin_statistics, em);
901 pthread_mutex_unlock(&ebpf_exit_cleanup);
902 }
903
@@ -1486,7 +1961,9 @@ static void vfs_collector(ebpf_module_t *em)
1961 int update_every = em->update_every;
1962 int counter = update_every - 1;
1963 int maps_per_core = em->maps_per_core;
1489 - while (!ebpf_exit_plugin) {
1964 + uint32_t running_time = 0;
1965 + uint32_t lifetime = em->lifetime;
1966 + while (!ebpf_exit_plugin && running_time < lifetime) {
1967 (void)heartbeat_next(&hb, USEC_PER_SEC);
1968 if (ebpf_exit_plugin || ++counter != update_every)
1969 continue;
@@ -1519,6 +1996,15 @@ static void vfs_collector(ebpf_module_t *em)
1996
1997 pthread_mutex_unlock(&lock);
1998 pthread_mutex_unlock(&collect_data_mutex);
1999 +
2000 + pthread_mutex_lock(&ebpf_exit_cleanup);
2001 + if (running_time && !em->running_time)
2002 + running_time = update_every;
2003 + else
2004 + running_time += update_every;
2005 +
2006 + em->running_time = running_time;
2007 + pthread_mutex_unlock(&ebpf_exit_cleanup);
2008 }
2009 }
2010
@@ -1690,6 +2176,8 @@ static void ebpf_create_global_charts(ebpf_module_t *em)
2176 &vfs_publish_aggregated[NETDATA_KEY_PUBLISH_VFS_CREATE],
2177 1, em->update_every, NETDATA_EBPF_MODULE_NAME_VFS);
2178 }
2179 +
2180 + fflush(stdout);
2181 }
2182
2183 /**
@@ -1934,10 +2422,10 @@ void *ebpf_vfs_thread(void *ptr)
2422 pthread_mutex_lock(&lock);
2423 ebpf_create_global_charts(em);
2424 ebpf_update_stats(&plugin_statistics, em);
1937 - ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps);
2425 + ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_ADD);
2426 #ifdef NETDATA_DEV_MODE
2427 if (ebpf_aral_vfs_pid)
1940 - ebpf_statistic_create_aral_chart(NETDATA_EBPF_VFS_ARAL_NAME, em);
2428 + vfs_disable_priority = ebpf_statistic_create_aral_chart(NETDATA_EBPF_VFS_ARAL_NAME, em);
2429 #endif
2430
2431 pthread_mutex_unlock(&lock);
collectors/ebpf.plugin/ebpf_vfs.h
+2 -1
@@ -3,8 +3,9 @@
3 #ifndef NETDATA_EBPF_VFS_H
4 #define NETDATA_EBPF_VFS_H 1
5
6 -// Module name
6 +// Module name & description
7 #define NETDATA_EBPF_MODULE_NAME_VFS "vfs"
8 +#define NETDATA_EBPF_VFS_MODULE_DESC "Monitor VFS (Virtual File System) functions. This thread is integrated with apps and cgroup."
9
10 #define NETDATA_DIRECTORY_VFS_CONFIG_FILE "vfs.conf"
11
docs/cloud/netdata-functions.md
+1
@@ -33,6 +33,7 @@ functions - [plugins.d](https://github.com/netdata/netdata/blob/master/collector
33 | Function | Description | plugin - module |
34 | :-- | :-- | :-- |
35 | processes | Detailed information on the currently running processes on the node. | [apps.plugin](https://github.com/netdata/netdata/blob/master/collectors/apps.plugin/README.md) |
36 +| ebpf_thread | Controller for eBPF threads. | [ebpf.plugin](https://github.com/netdata/netdata/blob/master/collectors/ebpf.plugin/README.md) |
37
38 If you have ideas or requests for other functions:
39 * open a [Feature request](https://github.com/netdata/netdata-cloud/issues/new?assignees=&labels=feature+request%2Cneeds+triage&template=FEAT_REQUEST.yml&title=%5BFeat%5D%3A+) on Netdata Cloud repo
libnetdata/ebpf/ebpf.c
+30 -19
@@ -391,9 +391,10 @@ static void ebpf_mount_name(char *out, size_t len, char *path, uint32_t kver, co
391 * Count the information from targets.
392 *
393 * @param report the output structure
394 - * @param targets vector with information about the eBPF plugin.
394 + * @param targets vector with information about the eBPF plugin.
395 + * @param value factor used to update calculation
396 */
396 -static void ebpf_stats_targets(ebpf_plugin_stats_t *report, netdata_ebpf_targets_t *targets)
397 +static void ebpf_stats_targets(ebpf_plugin_stats_t *report, netdata_ebpf_targets_t *targets, int value)
398 {
399 if (!targets) {
400 report->probes = report->tracepoints = report->trampolines = 0;
@@ -404,19 +405,19 @@ static void ebpf_stats_targets(ebpf_plugin_stats_t *report, netdata_ebpf_targets
405 while (targets[i].name) {
406 switch (targets[i].mode) {
407 case EBPF_LOAD_PROBE: {
407 - report->probes++;
408 + report->probes += value;
409 break;
410 }
411 case EBPF_LOAD_RETPROBE: {
411 - report->retprobes++;
412 + report->retprobes += value;
413 break;
414 }
415 case EBPF_LOAD_TRACEPOINT: {
415 - report->tracepoints++;
416 + report->tracepoints += value;
417 break;
418 }
419 case EBPF_LOAD_TRAMPOLINE: {
419 - report->trampolines++;
420 + report->trampolines += value;
421 break;
422 }
423 }
@@ -437,27 +438,30 @@ static void ebpf_stats_targets(ebpf_plugin_stats_t *report, netdata_ebpf_targets
438 */
439 void ebpf_update_stats(ebpf_plugin_stats_t *report, ebpf_module_t *em)
440 {
440 - report->threads++;
441 + int value;
442
443 // It is not necessary to report more information.
443 - if (em->enabled != NETDATA_THREAD_EBPF_RUNNING)
444 - return;
444 + if (em->enabled > NETDATA_THREAD_EBPF_FUNCTION_RUNNING)
445 + value = -1;
446 + else
447 + value = 1;
448
446 - report->running++;
449 + report->threads += value;
450 + report->running += value;
451
452 // In theory the `else if` is useless, because when this function is called, the module should not stay in
453 // EBPF_LOAD_PLAY_DICE. We have this additional condition to detect errors from developers.
454 if (em->load & EBPF_LOAD_LEGACY)
451 - report->legacy++;
455 + report->legacy += value;
456 else if (em->load & EBPF_LOAD_CORE)
453 - report->core++;
457 + report->core += value;
458
459 if (em->maps_per_core)
456 - report->hash_percpu++;
460 + report->hash_percpu += value;
461 else
458 - report->hash_unique++;
462 + report->hash_unique += value;
463
460 - ebpf_stats_targets(report, em->targets);
464 + ebpf_stats_targets(report, em->targets, value);
465 }
466
467 /**
@@ -528,8 +532,11 @@ void ebpf_update_kernel_memory(ebpf_plugin_stats_t *report, ebpf_local_maps_t *m
532 *
533 * @param report the output structure
534 * @param map pointer to a map. Last map must fish with name = NULL
535 + * @param action should plugin add or remove values from amount.
536 */
532 -void ebpf_update_kernel_memory_with_vector(ebpf_plugin_stats_t *report, ebpf_local_maps_t *maps)
537 +void ebpf_update_kernel_memory_with_vector(ebpf_plugin_stats_t *report,
538 + ebpf_local_maps_t *maps,
539 + ebpf_stats_action_t action)
540 {
541 if (!maps)
542 return;
@@ -541,7 +548,7 @@ void ebpf_update_kernel_memory_with_vector(ebpf_plugin_stats_t *report, ebpf_loc
548 if (fd == ND_EBPF_MAP_FD_NOT_INITIALIZED)
549 continue;
550
544 - ebpf_update_kernel_memory(report, map, EBPF_ACTION_STAT_ADD);
551 + ebpf_update_kernel_memory(report, map, action);
552 }
553 }
554
@@ -1238,6 +1245,9 @@ void ebpf_update_module_using_config(ebpf_module_t *modules, netdata_ebpf_load_m
1245 modules->pid_map_size = (uint32_t)appconfig_get_number(modules->cfg, EBPF_GLOBAL_SECTION, EBPF_CFG_PID_SIZE,
1246 modules->pid_map_size);
1247
1248 + modules->lifetime = (uint32_t) appconfig_get_number(modules->cfg, EBPF_GLOBAL_SECTION,
1249 + EBPF_CFG_LIFETIME, EBPF_DEFAULT_LIFETIME);
1250 +
1251 char *value = ebpf_convert_load_mode_to_string(modules->load & NETDATA_EBPF_LOAD_METHODS);
1252 char *type_format = appconfig_get(modules->cfg, EBPF_GLOBAL_SECTION, EBPF_CFG_TYPE_FORMAT, value);
1253 netdata_ebpf_load_mode_t load = epbf_convert_string_to_load_mode(type_format);
@@ -1258,7 +1268,7 @@ void ebpf_update_module_using_config(ebpf_module_t *modules, netdata_ebpf_load_m
1268 modules->maps_per_core = CONFIG_BOOLEAN_NO;
1269
1270 #ifdef NETDATA_DEV_MODE
1261 - netdata_log_info("The thread %s was configured with: mode = %s; update every = %d; apps = %s; cgroup = %s; ebpf type format = %s; ebpf co-re tracing = %s; collect pid = %s; maps per core = %s",
1271 + netdata_log_info("The thread %s was configured with: mode = %s; update every = %d; apps = %s; cgroup = %s; ebpf type format = %s; ebpf co-re tracing = %s; collect pid = %s; maps per core = %s, lifetime=%u",
1272 modules->thread_name,
1273 load_mode,
1274 modules->update_every,
@@ -1267,7 +1277,8 @@ void ebpf_update_module_using_config(ebpf_module_t *modules, netdata_ebpf_load_m
1277 type_format,
1278 core_attach,
1279 collect_pid,
1270 - (modules->maps_per_core)?"enabled":"disabled"
1280 + (modules->maps_per_core)?"enabled":"disabled",
1281 + modules->lifetime
1282 );
1283 #endif
1284 }
libnetdata/ebpf/ebpf.h
+20 -6
@@ -43,6 +43,7 @@
43 #define EBPF_CFG_MAPS_PER_CORE "maps per core"
44
45 #define EBPF_CFG_UPDATE_EVERY "update every"
46 +#define EBPF_CFG_LIFETIME "lifetime"
47 #define EBPF_CFG_UPDATE_APPS_EVERY_DEFAULT 10
48 #define EBPF_CFG_PID_SIZE "pid table size"
49 #define EBPF_CFG_APPLICATION "apps"
@@ -270,15 +271,17 @@ typedef enum netdata_apps_integration_flags {
271 #define NETDATA_EBPF_STAT_DIMENSION_ARAL "aral"
272
273 enum ebpf_threads_status {
273 - NETDATA_THREAD_EBPF_RUNNING,
274 - NETDATA_THREAD_EBPF_STOPPING,
275 - NETDATA_THREAD_EBPF_STOPPED,
276 - NETDATA_THREAD_EBPF_NOT_RUNNING
274 + NETDATA_THREAD_EBPF_RUNNING, // started by plugin
275 + NETDATA_THREAD_EBPF_FUNCTION_RUNNING, // started by function
276 + NETDATA_THREAD_EBPF_STOPPING, // stopping thread
277 + NETDATA_THREAD_EBPF_STOPPED, // thread stopped
278 + NETDATA_THREAD_EBPF_NOT_RUNNING // thread was never started
279 };
280
281 typedef struct ebpf_module {
282 const char *thread_name;
283 const char *config_name;
284 + const char *thread_description;
285 enum ebpf_threads_status enabled;
286 void *(*start_routine)(void *);
287 int update_every;
@@ -306,8 +309,16 @@ typedef struct ebpf_module {
309 char memory_usage[NETDATA_EBPF_CHART_MEM_LENGTH];
310 char memory_allocations[NETDATA_EBPF_CHART_MEM_LENGTH];
311 int maps_per_core;
312 +
313 + // period to run
314 + uint32_t running_time; // internal usage, this is used to reset a value when a new request happens.
315 + uint32_t lifetime;
316 } ebpf_module_t;
317
318 +#define EBPF_DEFAULT_LIFETIME 300
319 +// This will be present until all functions are merged
320 +#define EBPF_NON_FUNCTION_LIFE_TIME 86400
321 +
322 int ebpf_get_kernel_version();
323 int get_redhat_release();
324 int has_condition_to_run(int version);
@@ -336,6 +347,7 @@ void ebpf_update_map_size(struct bpf_map *map, ebpf_local_maps_t *lmap, ebpf_mod
347 typedef struct netdata_ebpf_histogram {
348 char *name;
349 char *title;
350 + char *ctx;
351 int order;
352 uint64_t histogram[NETDATA_EBPF_HIST_MAX_BINS];
353 } netdata_ebpf_histogram_t;
@@ -425,9 +437,11 @@ void ebpf_update_map_type(struct bpf_map *map, ebpf_local_maps_t *w);
437 void ebpf_define_map_type(ebpf_local_maps_t *maps, int maps_per_core, int kver);
438 #endif
439
428 -void ebpf_update_kernel_memory_with_vector(ebpf_plugin_stats_t *report, ebpf_local_maps_t *maps);
440 +void ebpf_update_kernel_memory_with_vector(ebpf_plugin_stats_t *report, ebpf_local_maps_t *maps,
441 + ebpf_stats_action_t action);
442 void ebpf_update_kernel_memory(ebpf_plugin_stats_t *report, ebpf_local_maps_t *map, ebpf_stats_action_t action);
430 -void ebpf_statistic_create_aral_chart(char *name, ebpf_module_t *em);
443 +int ebpf_statistic_create_aral_chart(char *name, ebpf_module_t *em);
444 +void ebpf_statistic_obsolete_aral_chart(ebpf_module_t *em, int prio);
445 void ebpf_send_data_aral_chart(ARAL *memory, ebpf_module_t *em);
446
447 #endif /* NETDATA_EBPF_H */
netdata.spec.in
+1
@@ -530,6 +530,7 @@ rm -rf "${RPM_BUILD_ROOT}"
530 %{_libexecdir}/%{name}/plugins.d/system-info.sh
531 %{_libexecdir}/%{name}/plugins.d/tc-qos-helper.sh
532 %{_libexecdir}/%{name}/plugins.d/template_dim.sh
533 +%{_libexecdir}/%{name}/plugins.d/ebpf_thread_function.sh
534
535 # cgroup-network detects the network interfaces of CGROUPs
536 # it must be able to use setns() and run cgroup-network-helper.sh as root
tests/Makefile.am
+3
@@ -9,6 +9,7 @@ CLEANFILES = \
9 $(srcdir)/urls/request.sh \
10 $(srcdir)/alarm_repetition/alarm.sh \
11 $(srcdir)/template_dimension/template_dim.sh \
12 + $(srcdir)/ebpf/ebpf_thread_function.sh \
13 $(NULL)
14
15 include $(top_srcdir)/build/subst.inc
@@ -20,6 +21,7 @@ dist_noinst_DATA = \
21 $(srcdir)/urls/request.sh.in \
22 $(srcdir)/alarm_repetition/alarm.sh.in \
23 $(srcdir)/template_dimension/template_dim.sh.in \
24 + $(srcdir)/ebpf/ebpf_thread_function.sh.in \
25 $(NULL)
26
27 dist_plugins_SCRIPTS = \
@@ -28,6 +30,7 @@ dist_plugins_SCRIPTS = \
30 $(srcdir)/urls/request.sh \
31 $(srcdir)/alarm_repetition/alarm.sh \
32 $(srcdir)/template_dimension/template_dim.sh \
33 + $(srcdir)/ebpf/ebpf_thread_function.sh \
34 $(NULL)
35
36 dist_noinst_SCRIPTS = \
tests/ebpf/ebpf.d.conf new
+28
@@ -0,0 +1,28 @@
1 +[global]
2 + ebpf load mode = entry
3 + apps = yes
4 + cgroups = no
5 + update every = 5
6 + pid table size = 32768
7 + btf path = /sys/kernel/btf/
8 + maps per core = yes
9 + life time = 300
10 +
11 +[ebpf programs]
12 + cachestat = no
13 + dcstat = no
14 + disk = no
15 + fd = no
16 + filesystem = no
17 + hardirq = no
18 + mdflush = no
19 + mount = no
20 + oomkill = no
21 + process = no
22 + shm = no
23 + socket = no
24 + softirq = no
25 + sync = no
26 + swap = no
27 + vfs = no
28 + network connections = no
tests/ebpf/ebpf_thread_function.sh new
+52
@@ -0,0 +1,52 @@
1 +#!/bin/bash
2 +
3 +netdata_ebpf_test_functions() {
4 + echo "QUERYING: ${1}"
5 + curl -k -o /tmp/ebpf_netdata_test_functions.txt "${1}"
6 + TEST=$?
7 + if [ $TEST -ne 0 ]; then
8 + echo "Cannot request run a for ${1}. See '/tmp/ebpf_netdata_test_functions.txt' for more details."
9 + exit 1
10 + fi
11 +
12 + grep "${2}" /tmp/ebpf_netdata_test_functions.txt >/dev/null
13 + TEST=$?
14 + if [ $TEST -ne 0 ]; then
15 + echo "Cannot find ${2} in the output. See '/tmp/ebpf_netdata_test_functions.txt' for more details.."
16 + exit 1
17 + fi
18 +
19 + rm /tmp/ebpf_netdata_test_functions.txt
20 +}
21 +
22 +MURL="http://127.0.0.1:19999"
23 +INTERVAL=60
24 +
25 +if [ -n "$1" ]; then
26 + MURL="$1"
27 +fi
28 +
29 +# Check function loaded
30 +netdata_ebpf_test_functions "${MURL}/api/v1/functions" "ebpf_thread"
31 +
32 +# Check function help
33 +netdata_ebpf_test_functions "${MURL}/api/v1/function?function=ebpf_thread%20help" "allows user to control eBPF threads"
34 +
35 +#Test default request
36 +netdata_ebpf_test_functions "${MURL}/api/v1/function?function=ebpf_thread" "columns"
37 +
38 +#Test thread requests . The mdflush is not enabled, because it is not present in all distributions by default.
39 +#Socket is not in the list, because it will have a complete refactory with next PR
40 +for THREAD in "cachestat" "dc" "disk" "fd" "filesystem" "hardirq" "mount" "oomkill" "process" "shm" "softirq" "sync" "swap" "vfs" ;
41 +do
42 + echo "TESTING ${THREAD}"
43 + netdata_ebpf_test_functions "${MURL}/api/v1/function?function=ebpf_thread%20enable:${THREAD}:${INTERVAL}%20thread:${THREAD}"
44 + sleep 17
45 + netdata_ebpf_test_functions "${MURL}/api/v1/function?function=ebpf_thread%20thread:${THREAD}" "running"
46 + sleep 17
47 + netdata_ebpf_test_functions "${MURL}/api/v1/function?function=ebpf_thread%20disable:${THREAD}"
48 + sleep 6
49 + netdata_ebpf_test_functions "${MURL}/api/v1/function?function=ebpf_thread%20thread:${THREAD}" "stopped"
50 + sleep 6
51 +done
52 +
tests/ebpf/ebpf_thread_function.sh.in new
+52
@@ -0,0 +1,52 @@
1 +#!/bin/bash
2 +
3 +netdata_ebpf_test_functions() {
4 + echo "QUERYING: ${1}"
5 + curl -k -o /tmp/ebpf_netdata_test_functions.txt "${1}"
6 + TEST=$?
7 + if [ $TEST -ne 0 ]; then
8 + echo "Cannot request run a for ${1}. See '/tmp/ebpf_netdata_test_functions.txt' for more details."
9 + exit 1
10 + fi
11 +
12 + grep "${2}" /tmp/ebpf_netdata_test_functions.txt >/dev/null
13 + TEST=$?
14 + if [ $TEST -ne 0 ]; then
15 + echo "Cannot find ${2} in the output. See '/tmp/ebpf_netdata_test_functions.txt' for more details.."
16 + exit 1
17 + fi
18 +
19 + rm /tmp/ebpf_netdata_test_functions.txt
20 +}
21 +
22 +MURL="http://127.0.0.1:19999"
23 +INTERVAL=60
24 +
25 +if [ -n "$1" ]; then
26 + MURL="$1"
27 +fi
28 +
29 +# Check function loaded
30 +netdata_ebpf_test_functions "${MURL}/api/v1/functions" "ebpf_thread"
31 +
32 +# Check function help
33 +netdata_ebpf_test_functions "${MURL}/api/v1/function?function=ebpf_thread%20help" "allows user to control eBPF threads"
34 +
35 +#Test default request
36 +netdata_ebpf_test_functions "${MURL}/api/v1/function?function=ebpf_thread" "columns"
37 +
38 +#Test thread requests . The mdflush is not enabled, because it is not present in all distributions by default.
39 +#Socket is not in the list, because it will have a complete refactory with next PR
40 +for THREAD in "cachestat" "dc" "disk" "fd" "filesystem" "hardirq" "mount" "oomkill" "process" "shm" "softirq" "sync" "swap" "vfs" ;
41 +do
42 + echo "TESTING ${THREAD}"
43 + netdata_ebpf_test_functions "${MURL}/api/v1/function?function=ebpf_thread%20enable:${THREAD}:${INTERVAL}%20thread:${THREAD}"
44 + sleep 17
45 + netdata_ebpf_test_functions "${MURL}/api/v1/function?function=ebpf_thread%20thread:${THREAD}" "running"
46 + sleep 17
47 + netdata_ebpf_test_functions "${MURL}/api/v1/function?function=ebpf_thread%20disable:${THREAD}"
48 + sleep 6
49 + netdata_ebpf_test_functions "${MURL}/api/v1/function?function=ebpf_thread%20thread:${THREAD}" "stopped"
50 + sleep 6
51 +done
52 +
web/gui/dashboard_info.js
+5 -1
@@ -4935,7 +4935,11 @@ netdataDashboard.context = {
4935 },
4936
4937 'netdata.ebpf_threads': {
4938 - info: 'Show total number of threads and number of active threads. For more details about the threads, see the <a href="https://learn.netdata.cloud/docs/agent/collectors/ebpf.plugin#ebpf-programs-configuration-options" target="_blank">official documentation</a>.'
4938 + info: 'Show thread status. Threads running have value 1 an stopped value 0. For more details about the threads, see the <a href="https://learn.netdata.cloud/docs/agent/collectors/ebpf.plugin#ebpf-programs-configuration-options" target="_blank">official documentation</a>.'
4939 + },
4940 +
4941 + 'netdata.ebpf_life_time': {
4942 + info: 'Time remaining for thread shutdown itself.'
4943 },
4944
4945 'netdata.ebpf_load_methods': {