@cryptotaxi247 / netdata-1 / commits / 0dbf4bb90

Prepare to functions (eBPF) (#16788)

thiagoftsm committed Mar 1, 2024 at 16:36 UTC 0dbf4bb90cdb5be417afbebfbbfb74d345b7ef10
21 files changed +1111 -1305
src/collectors/ebpf.plugin/ebpf.c
+5 -6
@@ -4032,6 +4032,7 @@ int main(int argc, char **argv)
4032 heartbeat_t hb;
4033 heartbeat_init(&hb);
4034 int update_apps_every = (int) EBPF_CFG_UPDATE_APPS_EVERY_DEFAULT;
4035 + int max_period = update_apps_every * EBPF_CLEANUP_FACTOR;
4036 int update_apps_list = update_apps_every - 1;
4037 int process_maps_per_core = ebpf_modules[EBPF_MODULE_PROCESS_IDX].maps_per_core;
4038 //Plugin will be killed when it receives a signal
@@ -4047,19 +4048,17 @@ int main(int argc, char **argv)
4048 fflush(stdout);
4049 }
4050
4050 - pthread_mutex_lock(&ebpf_exit_cleanup);
4051 - pthread_mutex_lock(&collect_data_mutex);
4051 if (++update_apps_list == update_apps_every) {
4052 update_apps_list = 0;
4054 - cleanup_exited_pids();
4053 + pthread_mutex_lock(&lock);
4054 + pthread_mutex_lock(&collect_data_mutex);
4055 + ebpf_cleanup_exited_pids(max_period);
4056 collect_data_for_all_processes(process_pid_fd, process_maps_per_core);
4057
4057 - pthread_mutex_lock(&lock);
4058 ebpf_create_apps_charts(apps_groups_root_target);
4059 + pthread_mutex_unlock(&collect_data_mutex);
4060 pthread_mutex_unlock(&lock);
4061 }
4061 - pthread_mutex_unlock(&collect_data_mutex);
4062 - pthread_mutex_unlock(&ebpf_exit_cleanup);
4062 }
4063
4064 ebpf_stop_threads(0);
src/collectors/ebpf.plugin/ebpf.d.conf
+5 -5
@@ -58,20 +58,20 @@
58 # When plugin detects that system has support to BTF, it enables integration with apps.plugin.
59 #
60 [ebpf programs]
61 - cachestat = yes
61 + cachestat = no
62 dcstat = no
63 disk = no
64 - fd = yes
64 + fd = no
65 filesystem = no
66 hardirq = no
67 mdflush = no
68 mount = yes
69 oomkill = yes
70 - process = yes
71 - shm = yes
70 + process = no
71 + shm = no
72 socket = no
73 softirq = yes
74 sync = no
75 - swap = yes
75 + swap = no
76 vfs = no
77 network connections = no
src/collectors/ebpf.plugin/ebpf.d/cachestat.conf
+1 -1
@@ -37,6 +37,6 @@
37 # pid table size = 32768
38 ebpf type format = auto
39 ebpf co-re tracing = trampoline
40 - collect pid = real parent
40 + collect pid = all
41 # maps per core = yes
42 lifetime = 300
src/collectors/ebpf.plugin/ebpf.d/dcstat.conf
+1 -1
@@ -35,6 +35,6 @@
35 # pid table size = 32768
36 ebpf type format = auto
37 ebpf co-re tracing = trampoline
38 - collect pid = real parent
38 + collect pid = all
39 # maps per core = yes
40 lifetime = 300
src/collectors/ebpf.plugin/ebpf.d/process.conf
+1 -1
@@ -26,6 +26,6 @@
26 # cgroups = no
27 # update every = 10
28 # pid table size = 32768
29 - collect pid = real parent
29 + collect pid = all
30 # maps per core = yes
31 lifetime = 300
src/collectors/ebpf.plugin/ebpf.d/shm.conf
+1
@@ -31,6 +31,7 @@
31 # pid table size = 32768
32 ebpf type format = auto
33 ebpf co-re tracing = trampoline
34 + collect pid = all
35 # maps per core = yes
36 lifetime = 300
37
src/collectors/ebpf.plugin/ebpf.d/swap.conf
+1
@@ -30,5 +30,6 @@
30 # pid table size = 32768
31 ebpf type format = auto
32 ebpf co-re tracing = trampoline
33 + collect pid = all
34 # maps per core = yes
35 lifetime = 300
src/collectors/ebpf.plugin/ebpf_apps.c
+59 -367
@@ -7,24 +7,6 @@
7 // ----------------------------------------------------------------------------
8 // ARAL vectors used to speed up processing
9 ARAL *ebpf_aral_apps_pid_stat = NULL;
10 -ARAL *ebpf_aral_process_stat = NULL;
11 -ARAL *ebpf_aral_socket_pid = NULL;
12 -ARAL *ebpf_aral_cachestat_pid = NULL;
13 -ARAL *ebpf_aral_dcstat_pid = NULL;
14 -ARAL *ebpf_aral_vfs_pid = NULL;
15 -ARAL *ebpf_aral_fd_pid = NULL;
16 -ARAL *ebpf_aral_shm_pid = NULL;
17 -
18 -// ----------------------------------------------------------------------------
19 -// Global vectors used with apps
20 -ebpf_socket_publish_apps_t **socket_bandwidth_curr = NULL;
21 -netdata_publish_cachestat_t **cachestat_pid = NULL;
22 -netdata_publish_dcstat_t **dcstat_pid = NULL;
23 -netdata_publish_swap_t **swap_pid = NULL;
24 -netdata_publish_vfs_t **vfs_pid = NULL;
25 -netdata_fd_stat_t **fd_pid = NULL;
26 -netdata_publish_shm_t **shm_pid = NULL;
27 -ebpf_process_stat_t **global_process_stats = NULL;
10
11 /**
12 * eBPF ARAL Init
@@ -41,8 +23,6 @@ void ebpf_aral_init(void)
23
24 ebpf_aral_apps_pid_stat = ebpf_allocate_pid_aral("ebpf_pid_stat", sizeof(struct ebpf_pid_stat));
25
44 - ebpf_aral_process_stat = ebpf_allocate_pid_aral(NETDATA_EBPF_PROC_ARAL_NAME, sizeof(ebpf_process_stat_t));
45 -
26 #ifdef NETDATA_DEV_MODE
27 netdata_log_info("Plugin is using ARAL with values %d", NETDATA_EBPF_ALLOC_MAX_PID);
28 #endif
@@ -72,266 +52,6 @@ void ebpf_pid_stat_release(struct ebpf_pid_stat *stat)
52 aral_freez(ebpf_aral_apps_pid_stat, stat);
53 }
54
75 -/*****************************************************************
76 - *
77 - * PROCESS ARAL FUNCTIONS
78 - *
79 - *****************************************************************/
80 -
81 -/**
82 - * eBPF process stat get
83 - *
84 - * Get a ebpf_pid_stat entry to be used with a specific PID.
85 - *
86 - * @return it returns the address on success.
87 - */
88 -ebpf_process_stat_t *ebpf_process_stat_get(void)
89 -{
90 - ebpf_process_stat_t *target = aral_mallocz(ebpf_aral_process_stat);
91 - memset(target, 0, sizeof(ebpf_process_stat_t));
92 - return target;
93 -}
94 -
95 -/**
96 - * eBPF process release
97 - *
98 - * @param stat Release a target after usage.
99 - */
100 -void ebpf_process_stat_release(ebpf_process_stat_t *stat)
101 -{
102 - aral_freez(ebpf_aral_process_stat, stat);
103 -}
104 -
105 -/*****************************************************************
106 - *
107 - * SOCKET ARAL FUNCTIONS
108 - *
109 - *****************************************************************/
110 -
111 -/**
112 - * eBPF socket Aral init
113 - *
114 - * Initiallize array allocator that will be used when integration with apps is enabled.
115 - */
116 -void ebpf_socket_aral_init()
117 -{
118 - ebpf_aral_socket_pid = ebpf_allocate_pid_aral(NETDATA_EBPF_SOCKET_ARAL_NAME, sizeof(ebpf_socket_publish_apps_t));
119 -}
120 -
121 -/**
122 - * eBPF socket get
123 - *
124 - * Get a ebpf_socket_publish_apps_t entry to be used with a specific PID.
125 - *
126 - * @return it returns the address on success.
127 - */
128 -ebpf_socket_publish_apps_t *ebpf_socket_stat_get(void)
129 -{
130 - ebpf_socket_publish_apps_t *target = aral_mallocz(ebpf_aral_socket_pid);
131 - memset(target, 0, sizeof(ebpf_socket_publish_apps_t));
132 - return target;
133 -}
134 -
135 -/*****************************************************************
136 - *
137 - * CACHESTAT ARAL FUNCTIONS
138 - *
139 - *****************************************************************/
140 -
141 -/**
142 - * eBPF Cachestat Aral init
143 - *
144 - * Initiallize array allocator that will be used when integration with apps is enabled.
145 - */
146 -void ebpf_cachestat_aral_init()
147 -{
148 - ebpf_aral_cachestat_pid = ebpf_allocate_pid_aral(NETDATA_EBPF_CACHESTAT_ARAL_NAME, sizeof(netdata_publish_cachestat_t));
149 -}
150 -
151 -/**
152 - * eBPF publish cachestat get
153 - *
154 - * Get a netdata_publish_cachestat_t entry to be used with a specific PID.
155 - *
156 - * @return it returns the address on success.
157 - */
158 -netdata_publish_cachestat_t *ebpf_publish_cachestat_get(void)
159 -{
160 - netdata_publish_cachestat_t *target = aral_mallocz(ebpf_aral_cachestat_pid);
161 - memset(target, 0, sizeof(netdata_publish_cachestat_t));
162 - return target;
163 -}
164 -
165 -/**
166 - * eBPF cachestat release
167 - *
168 - * @param stat Release a target after usage.
169 - */
170 -void ebpf_cachestat_release(netdata_publish_cachestat_t *stat)
171 -{
172 - aral_freez(ebpf_aral_cachestat_pid, stat);
173 -}
174 -
175 -/*****************************************************************
176 - *
177 - * DCSTAT ARAL FUNCTIONS
178 - *
179 - *****************************************************************/
180 -
181 -/**
182 - * eBPF directory cache Aral init
183 - *
184 - * Initiallize array allocator that will be used when integration with apps is enabled.
185 - */
186 -void ebpf_dcstat_aral_init()
187 -{
188 - ebpf_aral_dcstat_pid = ebpf_allocate_pid_aral(NETDATA_EBPF_DCSTAT_ARAL_NAME, sizeof(netdata_publish_dcstat_t));
189 -}
190 -
191 -/**
192 - * eBPF publish dcstat get
193 - *
194 - * Get a netdata_publish_dcstat_t entry to be used with a specific PID.
195 - *
196 - * @return it returns the address on success.
197 - */
198 -netdata_publish_dcstat_t *ebpf_publish_dcstat_get(void)
199 -{
200 - netdata_publish_dcstat_t *target = aral_mallocz(ebpf_aral_dcstat_pid);
201 - memset(target, 0, sizeof(netdata_publish_dcstat_t));
202 - return target;
203 -}
204 -
205 -/**
206 - * eBPF dcstat release
207 - *
208 - * @param stat Release a target after usage.
209 - */
210 -void ebpf_dcstat_release(netdata_publish_dcstat_t *stat)
211 -{
212 - aral_freez(ebpf_aral_dcstat_pid, stat);
213 -}
214 -
215 -/*****************************************************************
216 - *
217 - * VFS ARAL FUNCTIONS
218 - *
219 - *****************************************************************/
220 -
221 -/**
222 - * eBPF VFS Aral init
223 - *
224 - * Initiallize array allocator that will be used when integration with apps is enabled.
225 - */
226 -void ebpf_vfs_aral_init()
227 -{
228 - ebpf_aral_vfs_pid = ebpf_allocate_pid_aral(NETDATA_EBPF_VFS_ARAL_NAME, sizeof(netdata_publish_vfs_t));
229 -}
230 -
231 -/**
232 - * eBPF publish VFS get
233 - *
234 - * Get a netdata_publish_vfs_t entry to be used with a specific PID.
235 - *
236 - * @return it returns the address on success.
237 - */
238 -netdata_publish_vfs_t *ebpf_vfs_get(void)
239 -{
240 - netdata_publish_vfs_t *target = aral_mallocz(ebpf_aral_vfs_pid);
241 - memset(target, 0, sizeof(netdata_publish_vfs_t));
242 - return target;
243 -}
244 -
245 -/**
246 - * eBPF VFS release
247 - *
248 - * @param stat Release a target after usage.
249 - */
250 -void ebpf_vfs_release(netdata_publish_vfs_t *stat)
251 -{
252 - aral_freez(ebpf_aral_vfs_pid, stat);
253 -}
254 -
255 -/*****************************************************************
256 - *
257 - * FD ARAL FUNCTIONS
258 - *
259 - *****************************************************************/
260 -
261 -/**
262 - * eBPF file descriptor Aral init
263 - *
264 - * Initiallize array allocator that will be used when integration with apps is enabled.
265 - */
266 -void ebpf_fd_aral_init()
267 -{
268 - ebpf_aral_fd_pid = ebpf_allocate_pid_aral(NETDATA_EBPF_FD_ARAL_NAME, sizeof(netdata_fd_stat_t));
269 -}
270 -
271 -/**
272 - * eBPF publish file descriptor get
273 - *
274 - * Get a netdata_fd_stat_t entry to be used with a specific PID.
275 - *
276 - * @return it returns the address on success.
277 - */
278 -netdata_fd_stat_t *ebpf_fd_stat_get(void)
279 -{
280 - netdata_fd_stat_t *target = aral_mallocz(ebpf_aral_fd_pid);
281 - memset(target, 0, sizeof(netdata_fd_stat_t));
282 - return target;
283 -}
284 -
285 -/**
286 - * eBPF file descriptor release
287 - *
288 - * @param stat Release a target after usage.
289 - */
290 -void ebpf_fd_release(netdata_fd_stat_t *stat)
291 -{
292 - aral_freez(ebpf_aral_fd_pid, stat);
293 -}
294 -
295 -/*****************************************************************
296 - *
297 - * SHM ARAL FUNCTIONS
298 - *
299 - *****************************************************************/
300 -
301 -/**
302 - * eBPF shared memory Aral init
303 - *
304 - * Initiallize array allocator that will be used when integration with apps is enabled.
305 - */
306 -void ebpf_shm_aral_init()
307 -{
308 - ebpf_aral_shm_pid = ebpf_allocate_pid_aral(NETDATA_EBPF_SHM_ARAL_NAME, sizeof(netdata_publish_shm_t));
309 -}
310 -
311 -/**
312 - * eBPF shared memory get
313 - *
314 - * Get a netdata_publish_shm_t entry to be used with a specific PID.
315 - *
316 - * @return it returns the address on success.
317 - */
318 -netdata_publish_shm_t *ebpf_shm_stat_get(void)
319 -{
320 - netdata_publish_shm_t *target = aral_mallocz(ebpf_aral_shm_pid);
321 - memset(target, 0, sizeof(netdata_publish_shm_t));
322 - return target;
323 -}
324 -
325 -/**
326 - * eBPF shared memory release
327 - *
328 - * @param stat Release a target after usage.
329 - */
330 -void ebpf_shm_release(netdata_publish_shm_t *stat)
331 -{
332 - aral_freez(ebpf_aral_shm_pid, stat);
333 -}
334 -
55 // ----------------------------------------------------------------------------
56 // internal flags
57 // handled in code (automatically set)
@@ -735,14 +455,19 @@ static inline int managed_log(struct ebpf_pid_stat *p, uint32_t log, int status)
455 *
456 * Get or allocate the PID entry for the specified pid.
457 *
738 - * @param pid the pid to search the data.
458 + * @param pid the pid to search the data.
459 + * @param tgid the task group id
460 *
461 * @return It returns the pid entry structure
462 */
742 -static inline struct ebpf_pid_stat *get_pid_entry(pid_t pid)
463 +ebpf_pid_stat_t *ebpf_get_pid_entry(pid_t pid, pid_t tgid)
464 {
744 - if (unlikely(ebpf_all_pids[pid]))
465 + ebpf_pid_stat_t *ptr = ebpf_all_pids[pid];
466 + if (unlikely(ptr)) {
467 + if (!ptr->ppid && tgid)
468 + ptr->ppid = tgid;
469 return ebpf_all_pids[pid];
470 + }
471
472 struct ebpf_pid_stat *p = ebpf_pid_stat_get();
473
@@ -753,6 +478,7 @@ static inline struct ebpf_pid_stat *get_pid_entry(pid_t pid)
478 ebpf_root_of_pids = p;
479
480 p->pid = pid;
481 + p->ppid = tgid;
482
483 ebpf_all_pids[pid] = p;
484 ebpf_all_pids_count++;
@@ -933,14 +659,14 @@ static inline int read_proc_pid_stat(struct ebpf_pid_stat *p, void *ptr)
659 *
660 * @return It returns 1 on success and 0 otherwise
661 */
936 -static inline int collect_data_for_pid(pid_t pid, void *ptr)
662 +static inline int ebpf_collect_data_for_pid(pid_t pid, void *ptr)
663 {
664 if (unlikely(pid < 0 || pid > pid_max)) {
665 netdata_log_error("Invalid pid %d read (expected %d to %d). Ignoring process.", pid, 0, pid_max);
666 return 0;
667 }
668
943 - struct ebpf_pid_stat *p = get_pid_entry(pid);
669 + ebpf_pid_stat_t *p = ebpf_get_pid_entry(pid, 0);
670 if (unlikely(!p || p->read))
671 return 0;
672 p->read = 1;
@@ -1146,7 +872,7 @@ static inline void post_aggregate_targets(struct ebpf_target *root)
872 *
873 * @param pid the PID that will be removed.
874 */
1149 -static inline void del_pid_entry(pid_t pid)
875 +static inline void ebpf_del_pid_entry(pid_t pid)
876 {
877 struct ebpf_pid_stat *p = ebpf_all_pids[pid];
878
@@ -1222,80 +948,24 @@ int get_pid_comm(pid_t pid, size_t n, char *dest)
948 return 0;
949 }
950
1225 -/**
1226 - * Cleanup variable from other threads
1227 - *
1228 - * @param pid current pid.
1229 - */
1230 -void cleanup_variables_from_other_threads(uint32_t pid)
1231 -{
1232 - // Clean cachestat structure
1233 - if (cachestat_pid) {
1234 - ebpf_cachestat_release(cachestat_pid[pid]);
1235 - cachestat_pid[pid] = NULL;
1236 - }
1237 -
1238 - // Clean directory cache structure
1239 - if (dcstat_pid) {
1240 - ebpf_dcstat_release(dcstat_pid[pid]);
1241 - dcstat_pid[pid] = NULL;
1242 - }
1243 -
1244 - // Clean swap structure
1245 - if (swap_pid) {
1246 - freez(swap_pid[pid]);
1247 - swap_pid[pid] = NULL;
1248 - }
1249 -
1250 - // Clean vfs structure
1251 - if (vfs_pid) {
1252 - ebpf_vfs_release(vfs_pid[pid]);
1253 - vfs_pid[pid] = NULL;
1254 - }
1255 -
1256 - // Clean fd structure
1257 - if (fd_pid) {
1258 - ebpf_fd_release(fd_pid[pid]);
1259 - fd_pid[pid] = NULL;
1260 - }
1261 -
1262 - // Clean shm structure
1263 - if (shm_pid) {
1264 - ebpf_shm_release(shm_pid[pid]);
1265 - shm_pid[pid] = NULL;
1266 - }
1267 -}
1268 -
951 /**
952 * Remove PIDs when they are not running more.
953 */
1272 -void cleanup_exited_pids()
954 +void ebpf_cleanup_exited_pids(int max)
955 {
956 struct ebpf_pid_stat *p = NULL;
957
958 for (p = ebpf_root_of_pids; p;) {
1277 - if (!p->updated && (!p->keep || p->keeploops > 0)) {
959 + if (p->not_updated > max) {
960 if (unlikely(debug_enabled && (p->keep || p->keeploops)))
961 debug_log(" > CLEANUP cannot keep exited process %d (%s) anymore - removing it.", p->pid, p->comm);
962
963 pid_t r = p->pid;
964 p = p->next;
965
1284 - // Clean process structure
1285 - if (global_process_stats) {
1286 - ebpf_process_stat_release(global_process_stats[r]);
1287 - global_process_stats[r] = NULL;
1288 - }
1289 -
1290 - cleanup_variables_from_other_threads(r);
1291 -
1292 - del_pid_entry(r);
1293 - } else {
1294 - if (unlikely(p->keep))
1295 - p->keeploops++;
1296 - p->keep = 0;
1297 - p = p->next;
966 + ebpf_del_pid_entry(r);
967 }
968 + p = p->next;
969 }
970 }
971
@@ -1327,7 +997,7 @@ static inline void read_proc_filesystem()
997 if (unlikely(endptr == de->d_name || *endptr != '\0'))
998 continue;
999
1330 - collect_data_for_pid(pid, NULL);
1000 + ebpf_collect_data_for_pid(pid, NULL);
1001 }
1002 closedir(dir);
1003 }
@@ -1382,6 +1052,31 @@ void ebpf_process_apps_accumulator(ebpf_process_stat_t *out, int maps_per_core)
1052 }
1053 }
1054
1055 +/**
1056 + * Sum values for pid
1057 + *
1058 + * @param structure to store result.
1059 + * @param root the structure with all available PIDs
1060 + */
1061 +void ebpf_process_sum_values_for_pids(ebpf_process_stat_t *process, struct ebpf_pid_on_target *root)
1062 +{
1063 + memset(process, 0, sizeof(ebpf_process_stat_t));
1064 + while (root) {
1065 + int32_t pid = root->pid;
1066 + ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(pid, 0);
1067 + if (local_pid) {
1068 + ebpf_process_stat_t *in = &local_pid->process;
1069 + process->task_err += in->task_err;
1070 + process->release_call += in->release_call;
1071 + process->exit_call += in->exit_call;
1072 + process->create_thread += in->create_thread;
1073 + process->create_process += in->create_process;
1074 + }
1075 +
1076 + root = root->next;
1077 + }
1078 +}
1079 +
1080 /**
1081 * Collect data for all process
1082 *
@@ -1414,42 +1109,31 @@ void collect_data_for_all_processes(int tbl_pid_stats_fd, int maps_per_core)
1109
1110 read_proc_filesystem();
1111
1417 - uint32_t key;
1112 pids = ebpf_root_of_pids; // global list of all processes running
1419 - // while (bpf_map_get_next_key(tbl_pid_stats_fd, &key, &next_key) == 0) {
1113
1114 if (tbl_pid_stats_fd != -1) {
1115 size_t length = sizeof(ebpf_process_stat_t);
1116 if (maps_per_core)
1117 length *= ebpf_nprocs;
1118
1426 - while (pids) {
1427 - key = pids->pid;
1428 -
1429 - ebpf_process_stat_t *w = global_process_stats[key];
1430 - if (!w) {
1431 - w = ebpf_process_stat_get();
1432 - global_process_stats[key] = w;
1433 - }
1119 + uint32_t key = 0, next_key = 0;
1120 + while (bpf_map_get_next_key(tbl_pid_stats_fd, &key, &next_key) == 0) {
1121 + ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(key, 0);
1122 + if (!local_pid)
1123 + goto end_process_loop;
1124
1125 + ebpf_process_stat_t *w = &local_pid->process;
1126 if (bpf_map_lookup_elem(tbl_pid_stats_fd, &key, process_stat_vector)) {
1436 - // Clean Process structures
1437 - ebpf_process_stat_release(w);
1438 - global_process_stats[key] = NULL;
1439 -
1440 - cleanup_variables_from_other_threads(key);
1441 -
1442 - pids = pids->next;
1443 - continue;
1127 + goto end_process_loop;
1128 }
1129
1130 ebpf_process_apps_accumulator(process_stat_vector, maps_per_core);
1131
1132 memcpy(w, process_stat_vector, sizeof(ebpf_process_stat_t));
1133
1134 +end_process_loop:
1135 memset(process_stat_vector, 0, length);
1451 -
1452 - pids = pids->next;
1136 + key = next_key;
1137 }
1138 }
1139
@@ -1465,4 +1149,12 @@ void collect_data_for_all_processes(int tbl_pid_stats_fd, int maps_per_core)
1149 aggregate_pid_on_target(pids->target, pids, NULL);
1150
1151 post_aggregate_targets(apps_groups_root_target);
1152 +
1153 + struct ebpf_target *w;
1154 + for (w = apps_groups_root_target; w; w = w->next) {
1155 + if (unlikely(!(w->processes)))
1156 + continue;
1157 +
1158 + ebpf_process_sum_values_for_pids(&w->process, w->root_pid);
1159 + }
1160 }
src/collectors/ebpf.plugin/ebpf_apps.h
+42 -61
@@ -43,6 +43,31 @@
43 #define EBPF_MAX_COMPARE_NAME 100
44 #define EBPF_MAX_NAME 100
45
46 +#define EBPF_CLEANUP_FACTOR 10
47 +
48 +// ----------------------------------------------------------------------------
49 +// Structures used to read information from kernel ring
50 +typedef struct ebpf_process_stat {
51 + uint64_t ct;
52 + uint32_t uid;
53 + uint32_t gid;
54 + char name[TASK_COMM_LEN];
55 +
56 + uint32_t tgid;
57 + uint32_t pid;
58 +
59 + //Counter
60 + uint32_t exit_call;
61 + uint32_t release_call;
62 + uint32_t create_process;
63 + uint32_t create_thread;
64 +
65 + //Counter
66 + uint32_t task_err;
67 +
68 + uint8_t removeme;
69 +} ebpf_process_stat_t;
70 +
71 // ----------------------------------------------------------------------------
72 // pid_stat
73 //
@@ -65,6 +90,8 @@ struct ebpf_target {
90 netdata_publish_vfs_t vfs;
91 netdata_fd_stat_t fd;
92 netdata_publish_shm_t shm;
93 + ebpf_process_stat_t process;
94 + ebpf_socket_publish_apps_t socket;
95
96 kernel_uint_t starttime;
97 kernel_uint_t collected_starttime;
@@ -88,7 +115,7 @@ extern struct ebpf_target *apps_groups_root_target;
115 extern struct ebpf_target *users_root_target;
116 extern struct ebpf_target *groups_root_target;
117
91 -struct ebpf_pid_stat {
118 +typedef struct ebpf_pid_stat {
119 int32_t pid;
120 char comm[EBPF_MAX_COMPARE_NAME + 1];
121 char *cmdline;
@@ -109,6 +136,16 @@ struct ebpf_pid_stat {
136 int sortlist; // higher numbers = top on the process tree
137
138 // each process gets a unique number
139 + netdata_publish_cachestat_t cachestat;
140 + netdata_publish_dcstat_t dc;
141 + netdata_fd_stat_t fd;
142 + ebpf_process_stat_t process;
143 + netdata_publish_shm_t shm;
144 + netdata_publish_swap_t swap;
145 + ebpf_socket_publish_apps_t socket;
146 + netdata_publish_vfs_t vfs;
147 +
148 + int not_updated;
149
150 struct ebpf_target *target; // app_groups.conf targets
151 struct ebpf_target *user_target; // uid based targets
@@ -117,6 +154,8 @@ struct ebpf_pid_stat {
154 usec_t stat_collected_usec;
155 usec_t last_stat_collected_usec;
156
157 + netdata_publish_cachestat_t cache;
158 +
159 char *stat_filename;
160 char *status_filename;
161 char *io_filename;
@@ -125,7 +164,7 @@ struct ebpf_pid_stat {
164 struct ebpf_pid_stat *parent;
165 struct ebpf_pid_stat *prev;
166 struct ebpf_pid_stat *next;
128 -};
167 +} ebpf_pid_stat_t;
168
169 // ----------------------------------------------------------------------------
170 // target
@@ -140,29 +179,6 @@ struct ebpf_pid_on_target {
179 struct ebpf_pid_on_target *next;
180 };
181
143 -// ----------------------------------------------------------------------------
144 -// Structures used to read information from kernel ring
145 -typedef struct ebpf_process_stat {
146 - uint64_t ct;
147 - uint32_t uid;
148 - uint32_t gid;
149 - char name[TASK_COMM_LEN];
150 -
151 - uint32_t tgid;
152 - uint32_t pid;
153 -
154 - //Counter
155 - uint32_t exit_call;
156 - uint32_t release_call;
157 - uint32_t create_process;
158 - uint32_t create_thread;
159 -
160 - //Counter
161 - uint32_t task_err;
162 -
163 - uint8_t removeme;
164 -} ebpf_process_stat_t;
165 -
182 /**
183 * Internal function used to write debug messages.
184 *
@@ -204,14 +220,6 @@ int get_pid_comm(pid_t pid, size_t n, char *dest);
220 void collect_data_for_all_processes(int tbl_pid_stats_fd, int maps_per_core);
221 void ebpf_process_apps_accumulator(ebpf_process_stat_t *out, int maps_per_core);
222
207 -extern ebpf_process_stat_t **global_process_stats;
208 -extern netdata_publish_cachestat_t **cachestat_pid;
209 -extern netdata_publish_dcstat_t **dcstat_pid;
210 -extern netdata_publish_swap_t **swap_pid;
211 -extern netdata_publish_vfs_t **vfs_pid;
212 -extern netdata_fd_stat_t **fd_pid;
213 -extern netdata_publish_shm_t **shm_pid;
214 -
223 // The default value is at least 32 times smaller than maximum number of PIDs allowed on system,
224 // this is only possible because we are using ARAL (https://github.com/netdata/netdata/tree/master/src/libnetdata/aral).
225 #ifndef NETDATA_EBPF_ALLOC_MAX_PID
@@ -221,35 +229,14 @@ extern netdata_publish_shm_t **shm_pid;
229
230 // ARAL Sectiion
231 extern void ebpf_aral_init(void);
224 -
225 -extern ebpf_process_stat_t *ebpf_process_stat_get(void);
226 -extern void ebpf_process_stat_release(ebpf_process_stat_t *stat);
232 +extern ebpf_pid_stat_t *ebpf_get_pid_entry(pid_t pid, pid_t tgid);
233 extern ebpf_process_stat_t *process_stat_vector;
234
229 -extern ARAL *ebpf_aral_socket_pid;
230 -void ebpf_socket_aral_init();
231 -ebpf_socket_publish_apps_t *ebpf_socket_stat_get(void);
232 -
233 -extern ARAL *ebpf_aral_cachestat_pid;
234 -void ebpf_cachestat_aral_init();
235 -netdata_publish_cachestat_t *ebpf_publish_cachestat_get(void);
236 -void ebpf_cachestat_release(netdata_publish_cachestat_t *stat);
237 -
238 -extern ARAL *ebpf_aral_dcstat_pid;
239 -void ebpf_dcstat_aral_init();
240 -netdata_publish_dcstat_t *ebpf_publish_dcstat_get(void);
241 -void ebpf_dcstat_release(netdata_publish_dcstat_t *stat);
242 -
235 extern ARAL *ebpf_aral_vfs_pid;
236 void ebpf_vfs_aral_init();
237 netdata_publish_vfs_t *ebpf_vfs_get(void);
238 void ebpf_vfs_release(netdata_publish_vfs_t *stat);
239
248 -extern ARAL *ebpf_aral_fd_pid;
249 -void ebpf_fd_aral_init();
250 -netdata_fd_stat_t *ebpf_fd_stat_get(void);
251 -void ebpf_fd_release(netdata_fd_stat_t *stat);
252 -
240 extern ARAL *ebpf_aral_shm_pid;
241 void ebpf_shm_aral_init();
242 netdata_publish_shm_t *ebpf_shm_stat_get(void);
@@ -258,14 +245,8 @@ void ebpf_shm_release(netdata_publish_shm_t *stat);
245 // ARAL Section end
246
247 // Threads integrated with apps
261 -extern ebpf_socket_publish_apps_t **socket_bandwidth_curr;
248 // Threads integrated with apps
249
250 #include "libnetdata/threads/threads.h"
251
266 -// ARAL variables
267 -extern ARAL *ebpf_aral_apps_pid_stat;
268 -extern ARAL *ebpf_aral_process_stat;
269 -#define NETDATA_EBPF_PROC_ARAL_NAME "ebpf_proc_stat"
270 -
252 #endif /* NETDATA_EBPF_APPS_H */
src/collectors/ebpf.plugin/ebpf_cachestat.c
+161 -122
@@ -58,9 +58,16 @@ 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
61 +struct netdata_static_thread ebpf_read_cachestat = {
62 + .name = "EBPF_READ_CACHESTAT",
63 + .config_section = NULL,
64 + .config_name = NULL,
65 + .env_name = NULL,
66 + .enabled = 1,
67 + .thread = NULL,
68 + .init_routine = NULL,
69 + .start_routine = NULL
70 +};
71
72 #ifdef LIBBPF_MAJOR_VERSION
73 /**
@@ -189,7 +196,7 @@ static int ebpf_cachestat_attach_probe(struct cachestat_bpf *obj)
196 obj->links.netdata_add_to_page_cache_lru_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_add_to_page_cache_lru_kprobe,
197 false,
198 cachestat_targets[NETDATA_KEY_CALLS_ADD_TO_PAGE_CACHE_LRU].name);
192 - int ret = libbpf_get_error(obj->links.netdata_add_to_page_cache_lru_kprobe);
199 + long ret = libbpf_get_error(obj->links.netdata_add_to_page_cache_lru_kprobe);
200 if (ret)
201 return -1;
202
@@ -455,6 +462,7 @@ void ebpf_obsolete_cachestat_apps_charts(struct ebpf_module *em)
462 {
463 struct ebpf_target *w;
464 int update_every = em->update_every;
465 + pthread_mutex_lock(&collect_data_mutex);
466 for (w = apps_groups_root_target; w; w = w->next) {
467 if (unlikely(!(w->charts_created & (1<<EBPF_MODULE_CACHESTAT_IDX))))
468 continue;
@@ -504,6 +512,7 @@ void ebpf_obsolete_cachestat_apps_charts(struct ebpf_module *em)
512 update_every);
513 w->charts_created &= ~(1<<EBPF_MODULE_CACHESTAT_IDX);
514 }
515 + pthread_mutex_unlock(&collect_data_mutex);
516 }
517
518 /**
@@ -517,6 +526,9 @@ static void ebpf_cachestat_exit(void *ptr)
526 {
527 ebpf_module_t *em = (ebpf_module_t *)ptr;
528
529 + if (ebpf_read_cachestat.thread)
530 + netdata_thread_cancel(*ebpf_read_cachestat.thread);
531 +
532 if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
533 pthread_mutex_lock(&lock);
534 if (em->cgroup_charts) {
@@ -530,12 +542,6 @@ static void ebpf_cachestat_exit(void *ptr)
542
543 ebpf_obsolete_cachestat_global(em);
544
533 -#ifdef NETDATA_DEV_MODE
534 - if (ebpf_aral_cachestat_pid)
535 - ebpf_statistic_obsolete_aral_chart(em, cachestat_disable_priority);
536 -#endif
537 -
538 -
545 fflush(stdout);
546 pthread_mutex_unlock(&lock);
547 }
@@ -660,13 +666,17 @@ static void cachestat_apps_accumulator(netdata_cachestat_pid_t *out, int maps_pe
666 {
667 int i, end = (maps_per_core) ? ebpf_nprocs : 1;
668 netdata_cachestat_pid_t *total = &out[0];
669 + uint64_t ct = total->ct;
670 for (i = 1; i < end; i++) {
671 netdata_cachestat_pid_t *w = &out[i];
672 total->account_page_dirtied += w->account_page_dirtied;
673 total->add_to_page_cache_lru += w->add_to_page_cache_lru;
674 total->mark_buffer_dirty += w->mark_buffer_dirty;
675 total->mark_page_accessed += w->mark_page_accessed;
676 + if (w->ct > ct)
677 + ct = w->ct;
678 }
679 + total->ct = ct;
680 }
681
682 /**
@@ -675,39 +685,18 @@ static void cachestat_apps_accumulator(netdata_cachestat_pid_t *out, int maps_pe
685 * Save the current values inside the structure
686 *
687 * @param out vector used to plot charts
678 - * @param publish vector with values read from hash tables.
688 + * @param in vector with values read from hash tables.
689 */
680 -static inline void cachestat_save_pid_values(netdata_publish_cachestat_t *out, netdata_cachestat_pid_t *publish)
690 +static inline void cachestat_save_pid_values(netdata_publish_cachestat_t *out, netdata_cachestat_pid_t *in)
691 {
692 + out->ct = in->ct;
693 if (!out->current.mark_page_accessed) {
683 - memcpy(&out->current, &publish[0], sizeof(netdata_cachestat_pid_t));
694 + memcpy(&out->current, &in[0], sizeof(netdata_cachestat_pid_t));
695 return;
696 }
697
698 memcpy(&out->prev, &out->current, sizeof(netdata_cachestat_pid_t));
688 - memcpy(&out->current, &publish[0], sizeof(netdata_cachestat_pid_t));
689 -}
690 -
691 -/**
692 - * Fill PID
693 - *
694 - * Fill PID structures
695 - *
696 - * @param current_pid pid that we are collecting data
697 - * @param out values read from hash tables;
698 - */
699 -static void cachestat_fill_pid(uint32_t current_pid, netdata_cachestat_pid_t *publish)
700 -{
701 - netdata_publish_cachestat_t *curr = cachestat_pid[current_pid];
702 - if (!curr) {
703 - curr = ebpf_publish_cachestat_get();
704 - cachestat_pid[current_pid] = curr;
705 -
706 - cachestat_save_pid_values(curr, publish);
707 - return;
708 - }
709 -
710 - cachestat_save_pid_values(curr, publish);
699 + memcpy(&out->current, &in[0], sizeof(netdata_cachestat_pid_t));
700 }
701
702 /**
@@ -717,32 +706,39 @@ static void cachestat_fill_pid(uint32_t current_pid, netdata_cachestat_pid_t *pu
706 *
707 * @param maps_per_core do I need to read all cores?
708 */
720 -static void ebpf_read_cachestat_apps_table(int maps_per_core)
709 +static void ebpf_read_cachestat_apps_table(int maps_per_core, int max_period)
710 {
711 netdata_cachestat_pid_t *cv = cachestat_vector;
723 - uint32_t key;
724 - struct ebpf_pid_stat *pids = ebpf_root_of_pids;
712 int fd = cachestat_maps[NETDATA_CACHESTAT_PID_STATS].map_fd;
713 size_t length = sizeof(netdata_cachestat_pid_t);
714 if (maps_per_core)
715 length *= ebpf_nprocs;
716
730 - while (pids) {
731 - key = pids->pid;
732 -
717 + uint32_t key = 0, next_key = 0;
718 + while (bpf_map_get_next_key(fd, &key, &next_key) == 0) {
719 if (bpf_map_lookup_elem(fd, &key, cv)) {
734 - pids = pids->next;
735 - continue;
720 + goto end_cachestat_loop;
721 }
722
723 cachestat_apps_accumulator(cv, maps_per_core);
724
740 - cachestat_fill_pid(key, cv);
725 + ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(key, cv->tgid);
726 + if (!local_pid)
727 + goto end_cachestat_loop;
728 +
729 + netdata_publish_cachestat_t *publish = &local_pid->cachestat;
730 + if (!publish->ct || publish->ct != cv->ct){
731 + cachestat_save_pid_values(publish, cv);
732 + local_pid->not_updated = 0;
733 + } else if (++local_pid->not_updated >= max_period) {
734 + bpf_map_delete_elem(fd, &key);
735 + local_pid->not_updated = 0;
736 + }
737
738 +end_cachestat_loop:
739 // We are cleaning to avoid passing data read from one process to other.
740 memset(cv, 0, length);
744 -
745 - pids = pids->next;
741 + key = next_key;
742 }
743 }
744
@@ -753,14 +749,8 @@ static void ebpf_read_cachestat_apps_table(int maps_per_core)
749 *
750 * @param maps_per_core do I need to read all cores?
751 */
756 -static void ebpf_update_cachestat_cgroup(int maps_per_core)
752 +static void ebpf_update_cachestat_cgroup()
753 {
758 - netdata_cachestat_pid_t *cv = cachestat_vector;
759 - int fd = cachestat_maps[NETDATA_CACHESTAT_PID_STATS].map_fd;
760 - size_t length = sizeof(netdata_cachestat_pid_t);
761 - if (maps_per_core)
762 - length *= ebpf_nprocs;
763 -
754 ebpf_cgroup_target_t *ect;
755 pthread_mutex_lock(&mutex_cgroup_shm);
756 for (ect = ebpf_cgroup_pids; ect; ect = ect->next) {
@@ -768,25 +758,115 @@ static void ebpf_update_cachestat_cgroup(int maps_per_core)
758 for (pids = ect->pids; pids; pids = pids->next) {
759 int pid = pids->pid;
760 netdata_cachestat_pid_t *out = &pids->cachestat;
771 - if (likely(cachestat_pid) && cachestat_pid[pid]) {
772 - netdata_publish_cachestat_t *in = cachestat_pid[pid];
761 + ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(pid, 0);
762 + if (local_pid) {
763 + netdata_publish_cachestat_t *in = &local_pid->cachestat;
764
765 memcpy(out, &in->current, sizeof(netdata_cachestat_pid_t));
775 - } else {
776 - memset(cv, 0, length);
777 - if (bpf_map_lookup_elem(fd, &pid, cv)) {
778 - continue;
779 - }
780 -
781 - cachestat_apps_accumulator(cv, maps_per_core);
782 -
783 - memcpy(out, cv, sizeof(netdata_cachestat_pid_t));
766 }
767 }
768 }
769 pthread_mutex_unlock(&mutex_cgroup_shm);
770 }
771
772 +/**
773 + * Cachestat sum PIDs
774 + *
775 + * Sum values for all PIDs associated to a group
776 + *
777 + * @param publish output structure.
778 + * @param root structure with listed IPs
779 + */
780 +void ebpf_cachestat_sum_pids(netdata_publish_cachestat_t *publish, struct ebpf_pid_on_target *root)
781 +{
782 + memcpy(&publish->prev, &publish->current,sizeof(publish->current));
783 + memset(&publish->current, 0, sizeof(publish->current));
784 +
785 + netdata_cachestat_pid_t *dst = &publish->current;
786 + while (root) {
787 + int32_t pid = root->pid;
788 + ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(pid, 0);
789 + if (local_pid) {
790 + netdata_publish_cachestat_t *w = &local_pid->cachestat;
791 + netdata_cachestat_pid_t *src = &w->current;
792 + dst->account_page_dirtied += src->account_page_dirtied;
793 + dst->add_to_page_cache_lru += src->add_to_page_cache_lru;
794 + dst->mark_buffer_dirty += src->mark_buffer_dirty;
795 + dst->mark_page_accessed += src->mark_page_accessed;
796 + }
797 +
798 + root = root->next;
799 + }
800 +}
801 +
802 +/**
803 + * Resume apps data
804 + */
805 +void ebpf_resume_apps_data()
806 +{
807 + struct ebpf_target *w;
808 +
809 + for (w = apps_groups_root_target; w; w = w->next) {
810 + if (unlikely(!(w->charts_created & (1 << EBPF_MODULE_CACHESTAT_IDX))))
811 + continue;
812 +
813 + ebpf_cachestat_sum_pids(&w->cachestat, w->root_pid);
814 + }
815 +}
816 +
817 +/**
818 + * Cachestat thread
819 + *
820 + * Thread used to generate cachestat charts.
821 + *
822 + * @param ptr a pointer to `struct ebpf_module`
823 + *
824 + * @return It always return NULL
825 + */
826 +void *ebpf_read_cachestat_thread(void *ptr)
827 +{
828 + heartbeat_t hb;
829 + heartbeat_init(&hb);
830 +
831 + ebpf_module_t *em = (ebpf_module_t *)ptr;
832 +
833 + int maps_per_core = em->maps_per_core;
834 + int update_every = em->update_every;
835 + int max_period = update_every * EBPF_CLEANUP_FACTOR;
836 +
837 + int counter = update_every - 1;
838 +
839 + uint32_t lifetime = em->lifetime;
840 + uint32_t running_time = 0;
841 + usec_t period = update_every * USEC_PER_SEC;
842 + while (!ebpf_plugin_exit && running_time < lifetime) {
843 + (void)heartbeat_next(&hb, period);
844 + if (ebpf_plugin_exit || ++counter != update_every)
845 + continue;
846 +
847 + netdata_thread_disable_cancelability();
848 +
849 + pthread_mutex_lock(&collect_data_mutex);
850 + ebpf_read_cachestat_apps_table(maps_per_core, max_period);
851 + ebpf_resume_apps_data();
852 + pthread_mutex_unlock(&collect_data_mutex);
853 +
854 + counter = 0;
855 +
856 + pthread_mutex_lock(&ebpf_exit_cleanup);
857 + if (running_time && !em->running_time)
858 + running_time = update_every;
859 + else
860 + running_time += update_every;
861 +
862 + em->running_time = running_time;
863 + pthread_mutex_unlock(&ebpf_exit_cleanup);
864 + netdata_thread_enable_cancelability();
865 + }
866 +
867 + return NULL;
868 +}
869 +
870 /**
871 * Create apps charts
872 *
@@ -916,7 +996,7 @@ static void cachestat_send_global(netdata_publish_cachestat_t *publish)
996
997 ebpf_one_dimension_write_charts(
998 NETDATA_EBPF_MEMORY_GROUP, NETDATA_CACHESTAT_DIRTY_CHART, ptr[NETDATA_CACHESTAT_IDX_DIRTY].dimension,
919 - cachestat_hash_values[NETDATA_KEY_CALLS_MARK_BUFFER_DIRTY]);
999 + (long long)cachestat_hash_values[NETDATA_KEY_CALLS_MARK_BUFFER_DIRTY]);
1000
1001 ebpf_one_dimension_write_charts(
1002 NETDATA_EBPF_MEMORY_GROUP, NETDATA_CACHESTAT_HIT_CHART, ptr[NETDATA_CACHESTAT_IDX_HIT].dimension, publish->hit);
@@ -926,35 +1006,6 @@ static void cachestat_send_global(netdata_publish_cachestat_t *publish)
1006 publish->miss);
1007 }
1008
929 -/**
930 - * Cachestat sum PIDs
931 - *
932 - * Sum values for all PIDs associated to a group
933 - *
934 - * @param publish output structure.
935 - * @param root structure with listed IPs
936 - */
937 -void ebpf_cachestat_sum_pids(netdata_publish_cachestat_t *publish, struct ebpf_pid_on_target *root)
938 -{
939 - memcpy(&publish->prev, &publish->current,sizeof(publish->current));
940 - memset(&publish->current, 0, sizeof(publish->current));
941 -
942 - netdata_cachestat_pid_t *dst = &publish->current;
943 - while (root) {
944 - int32_t pid = root->pid;
945 - netdata_publish_cachestat_t *w = cachestat_pid[pid];
946 - if (w) {
947 - netdata_cachestat_pid_t *src = &w->current;
948 - dst->account_page_dirtied += src->account_page_dirtied;
949 - dst->add_to_page_cache_lru += src->add_to_page_cache_lru;
950 - dst->mark_buffer_dirty += src->mark_buffer_dirty;
951 - dst->mark_page_accessed += src->mark_page_accessed;
952 - }
953 -
954 - root = root->next;
955 - }
956 -}
957 -
1009 /**
1010 * Send data to Netdata calling auxiliary functions.
1011 *
@@ -965,17 +1016,17 @@ void ebpf_cache_send_apps_data(struct ebpf_target *root)
1016 struct ebpf_target *w;
1017 collected_number value;
1018
1019 + pthread_mutex_lock(&collect_data_mutex);
1020 for (w = root; w; w = w->next) {
1021 if (unlikely(!(w->charts_created & (1<<EBPF_MODULE_CACHESTAT_IDX))))
1022 continue;
1023
972 - ebpf_cachestat_sum_pids(&w->cachestat, w->root_pid);
1024 netdata_cachestat_pid_t *current = &w->cachestat.current;
1025 netdata_cachestat_pid_t *prev = &w->cachestat.prev;
1026
1027 uint64_t mpa = current->mark_page_accessed - prev->mark_page_accessed;
1028 uint64_t mbd = current->mark_buffer_dirty - prev->mark_buffer_dirty;
978 - w->cachestat.dirty = mbd;
1029 + w->cachestat.dirty = (long long)mbd;
1030 uint64_t apcl = current->add_to_page_cache_lru - prev->add_to_page_cache_lru;
1031 uint64_t apd = current->account_page_dirtied - prev->account_page_dirtied;
1032
@@ -1001,6 +1052,7 @@ void ebpf_cache_send_apps_data(struct ebpf_target *root)
1052 write_chart_dimension("misses", value);
1053 ebpf_write_end_chart();
1054 }
1055 + pthread_mutex_unlock(&collect_data_mutex);
1056 }
1057
1058 /**
@@ -1045,7 +1097,7 @@ void ebpf_cachestat_calc_chart_values()
1097
1098 uint64_t mpa = current->mark_page_accessed - prev->mark_page_accessed;
1099 uint64_t mbd = current->mark_buffer_dirty - prev->mark_buffer_dirty;
1048 - ect->publish_cachestat.dirty = mbd;
1100 + ect->publish_cachestat.dirty = (long long)mbd;
1101 uint64_t apcl = current->add_to_page_cache_lru - prev->add_to_page_cache_lru;
1102 uint64_t apd = current->account_page_dirtied - prev->account_page_dirtied;
1103
@@ -1316,12 +1368,9 @@ static void cachestat_collector(ebpf_module_t *em)
1368 counter = 0;
1369 netdata_apps_integration_flags_t apps = em->apps_charts;
1370 ebpf_cachestat_read_global_tables(stats, maps_per_core);
1319 - pthread_mutex_lock(&collect_data_mutex);
1320 - if (apps)
1321 - ebpf_read_cachestat_apps_table(maps_per_core);
1371
1372 if (cgroups)
1324 - ebpf_update_cachestat_cgroup(maps_per_core);
1373 + ebpf_update_cachestat_cgroup();
1374
1375 pthread_mutex_lock(&lock);
1376
@@ -1330,16 +1379,10 @@ static void cachestat_collector(ebpf_module_t *em)
1379 if (apps & NETDATA_EBPF_APPS_FLAG_CHART_CREATED)
1380 ebpf_cache_send_apps_data(apps_groups_root_target);
1381
1333 -#ifdef NETDATA_DEV_MODE
1334 - if (ebpf_aral_cachestat_pid)
1335 - ebpf_send_data_aral_chart(ebpf_aral_cachestat_pid, em);
1336 -#endif
1337 -
1382 if (cgroups)
1383 ebpf_cachestat_send_cgroup_data(update_every);
1384
1385 pthread_mutex_unlock(&lock);
1342 - pthread_mutex_unlock(&collect_data_mutex);
1386
1387 pthread_mutex_lock(&ebpf_exit_cleanup);
1388 if (running_time && !em->running_time)
@@ -1414,17 +1457,10 @@ static void ebpf_create_memory_charts(ebpf_module_t *em)
1457 *
1458 * We are not testing the return, because callocz does this and shutdown the software
1459 * case it was not possible to allocate.
1417 - *
1418 - * @param apps is apps enabled?
1460 */
1420 -static void ebpf_cachestat_allocate_global_vectors(int apps)
1461 +static void ebpf_cachestat_allocate_global_vectors()
1462 {
1422 - if (apps) {
1423 - cachestat_pid = callocz((size_t)pid_max, sizeof(netdata_publish_cachestat_t *));
1424 - ebpf_cachestat_aral_init();
1425 - cachestat_vector = callocz((size_t)ebpf_nprocs, sizeof(netdata_cachestat_pid_t));
1426 - }
1427 -
1463 + cachestat_vector = callocz((size_t)ebpf_nprocs, sizeof(netdata_cachestat_pid_t));
1464 cachestat_values = callocz((size_t)ebpf_nprocs, sizeof(netdata_idx_t));
1465
1466 memset(cachestat_hash_values, 0, NETDATA_CACHESTAT_END * sizeof(netdata_idx_t));
@@ -1532,7 +1568,7 @@ void *ebpf_cachestat_thread(void *ptr)
1568 goto endcachestat;
1569 }
1570
1535 - ebpf_cachestat_allocate_global_vectors(em->apps_charts);
1571 + ebpf_cachestat_allocate_global_vectors();
1572
1573 int algorithms[NETDATA_CACHESTAT_END] = {
1574 NETDATA_EBPF_ABSOLUTE_IDX, NETDATA_EBPF_INCREMENTAL_IDX, NETDATA_EBPF_ABSOLUTE_IDX, NETDATA_EBPF_ABSOLUTE_IDX
@@ -1546,13 +1582,16 @@ void *ebpf_cachestat_thread(void *ptr)
1582 ebpf_update_stats(&plugin_statistics, em);
1583 ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_ADD);
1584 ebpf_create_memory_charts(em);
1549 -#ifdef NETDATA_DEV_MODE
1550 - if (ebpf_aral_cachestat_pid)
1551 - cachestat_disable_priority = ebpf_statistic_create_aral_chart(NETDATA_EBPF_CACHESTAT_ARAL_NAME, em);
1552 -#endif
1585
1586 pthread_mutex_unlock(&lock);
1587
1588 + ebpf_read_cachestat.thread = mallocz(sizeof(netdata_thread_t));
1589 + netdata_thread_create(ebpf_read_cachestat.thread,
1590 + ebpf_read_cachestat.name,
1591 + NETDATA_THREAD_OPTION_DEFAULT,
1592 + ebpf_read_cachestat_thread,
1593 + em);
1594 +
1595 cachestat_collector(em);
1596
1597 endcachestat:
src/collectors/ebpf.plugin/ebpf_cachestat.h
+2 -3
@@ -34,9 +34,6 @@
34 #define NETDATA_SYSTEMD_CACHESTAT_HIT_FILE_CONTEXT "services.cachestat_hits"
35 #define NETDATA_SYSTEMD_CACHESTAT_MISS_FILES_CONTEXT "services.cachestat_misses"
36
37 -// ARAL Name
38 -#define NETDATA_EBPF_CACHESTAT_ARAL_NAME "ebpf_cachestat"
39 -
37 // variables
38 enum cachestat_counters {
39 NETDATA_KEY_CALLS_ADD_TO_PAGE_CACHE_LRU,
@@ -82,6 +79,8 @@ typedef struct netdata_publish_cachestat_pid {
79 } netdata_cachestat_pid_t;
80
81 typedef struct netdata_publish_cachestat {
82 + uint64_t ct;
83 +
84 long long ratio;
85 long long dirty;
86 long long hit;
src/collectors/ebpf.plugin/ebpf_dcstat.c
+200 -170
@@ -59,9 +59,16 @@ 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
62 +struct netdata_static_thread ebpf_read_dcstat = {
63 + .name = "EBPF_READ_DCSTAT",
64 + .config_section = NULL,
65 + .config_name = NULL,
66 + .env_name = NULL,
67 + .enabled = 1,
68 + .thread = NULL,
69 + .init_routine = NULL,
70 + .start_routine = NULL
71 +};
72
73 #ifdef LIBBPF_MAJOR_VERSION
74 /**
@@ -120,7 +127,7 @@ static int ebpf_dc_attach_probes(struct dc_bpf *obj)
127 obj->links.netdata_d_lookup_kretprobe = bpf_program__attach_kprobe(obj->progs.netdata_d_lookup_kretprobe,
128 true,
129 dc_targets[NETDATA_DC_TARGET_D_LOOKUP].name);
123 - int ret = libbpf_get_error(obj->links.netdata_d_lookup_kretprobe);
130 + long ret = libbpf_get_error(obj->links.netdata_d_lookup_kretprobe);
131 if (ret)
132 return -1;
133
@@ -350,6 +357,7 @@ void ebpf_obsolete_dc_apps_charts(struct ebpf_module *em)
357 {
358 struct ebpf_target *w;
359 int update_every = em->update_every;
360 + pthread_mutex_lock(&collect_data_mutex);
361 for (w = apps_groups_root_target; w; w = w->next) {
362 if (unlikely(!(w->charts_created & (1<<EBPF_MODULE_DCSTAT_IDX))))
363 continue;
@@ -400,6 +408,7 @@ void ebpf_obsolete_dc_apps_charts(struct ebpf_module *em)
408
409 w->charts_created &= ~(1<<EBPF_MODULE_DCSTAT_IDX);
410 }
411 + pthread_mutex_unlock(&collect_data_mutex);
412 }
413
414 /**
@@ -445,6 +454,9 @@ static void ebpf_dcstat_exit(void *ptr)
454 {
455 ebpf_module_t *em = (ebpf_module_t *)ptr;
456
457 + if (ebpf_read_dcstat.thread)
458 + netdata_thread_cancel(*ebpf_read_dcstat.thread);
459 +
460 if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
461 pthread_mutex_lock(&lock);
462 if (em->cgroup_charts) {
@@ -458,11 +470,6 @@ static void ebpf_dcstat_exit(void *ptr)
470
471 ebpf_obsolete_dc_global(em);
472
461 -#ifdef NETDATA_DEV_MODE
462 - if (ebpf_aral_dcstat_pid)
463 - ebpf_statistic_obsolete_aral_chart(em, dcstat_disable_priority);
464 -#endif
465 -
473 fflush(stdout);
474 pthread_mutex_unlock(&lock);
475 }
@@ -494,6 +501,173 @@ static void ebpf_dcstat_exit(void *ptr)
501 *
502 *****************************************************************/
503
504 +/**
505 + * Apps Accumulator
506 + *
507 + * Sum all values read from kernel and store in the first address.
508 + *
509 + * @param out the vector with read values.
510 + * @param maps_per_core do I need to read all cores?
511 + */
512 +static void ebpf_dcstat_apps_accumulator(netdata_dcstat_pid_t *out, int maps_per_core)
513 +{
514 + int i, end = (maps_per_core) ? ebpf_nprocs : 1;
515 + netdata_dcstat_pid_t *total = &out[0];
516 + uint64_t ct = total->ct;
517 + for (i = 1; i < end; i++) {
518 + netdata_dcstat_pid_t *w = &out[i];
519 + total->cache_access += w->cache_access;
520 + total->file_system += w->file_system;
521 + total->not_found += w->not_found;
522 +
523 + if (w->ct > ct)
524 + ct = w->ct;
525 + }
526 + total->ct = ct;
527 +}
528 +
529 +/**
530 + * Read Directory Cache APPS table
531 + *
532 + * Read the apps table and store data inside the structure.
533 + *
534 + * @param maps_per_core do I need to read all cores?
535 + */
536 +static void ebpf_read_dc_apps_table(int maps_per_core, int max_period)
537 +{
538 + netdata_dcstat_pid_t *cv = dcstat_vector;
539 + int fd = dcstat_maps[NETDATA_DCSTAT_PID_STATS].map_fd;
540 + size_t length = sizeof(netdata_dcstat_pid_t);
541 + if (maps_per_core)
542 + length *= ebpf_nprocs;
543 +
544 + uint32_t key = 0, next_key = 0;
545 + while (bpf_map_get_next_key(fd, &key, &next_key) == 0) {
546 + if (bpf_map_lookup_elem(fd, &key, cv)) {
547 + goto end_dc_loop;
548 + }
549 +
550 + ebpf_dcstat_apps_accumulator(cv, maps_per_core);
551 +
552 + ebpf_pid_stat_t *pid_stat = ebpf_get_pid_entry(key, cv->tgid);
553 + if (pid_stat) {
554 + netdata_publish_dcstat_t *publish = &pid_stat->dc;
555 + if (!publish->ct || publish->ct != cv->ct) {
556 + memcpy(&publish->curr, &cv[0], sizeof(netdata_dcstat_pid_t));
557 + pid_stat->not_updated = 0;
558 + } else if (++pid_stat->not_updated >= max_period) {
559 + bpf_map_delete_elem(fd, &key);
560 + pid_stat->not_updated = 0;
561 + }
562 + }
563 +
564 +end_dc_loop:
565 + // We are cleaning to avoid passing data read from one process to other.
566 + memset(cv, 0, length);
567 + key = next_key;
568 + }
569 +}
570 +
571 +/**
572 + * Cachestat sum PIDs
573 + *
574 + * Sum values for all PIDs associated to a group
575 + *
576 + * @param publish output structure.
577 + * @param root structure with listed IPs
578 + */
579 +void ebpf_dcstat_sum_pids(netdata_publish_dcstat_t *publish, struct ebpf_pid_on_target *root)
580 +{
581 + memset(&publish->curr, 0, sizeof(netdata_dcstat_pid_t));
582 + netdata_dcstat_pid_t *dst = &publish->curr;
583 + while (root) {
584 + int32_t pid = root->pid;
585 + ebpf_pid_stat_t *pid_stat = ebpf_get_pid_entry(pid, 0);
586 + if (pid_stat) {
587 + netdata_publish_dcstat_t *w = &pid_stat->dc;
588 + netdata_dcstat_pid_t *src = &w->curr;
589 + dst->cache_access += src->cache_access;
590 + dst->file_system += src->file_system;
591 + dst->not_found += src->not_found;
592 + }
593 +
594 + root = root->next;
595 + }
596 +}
597 +
598 +/**
599 + * Resume apps data
600 + */
601 +void ebpf_dc_resume_apps_data()
602 +{
603 + struct ebpf_target *w;
604 +
605 + for (w = apps_groups_root_target; w; w = w->next) {
606 + if (unlikely(!(w->charts_created & (1<<EBPF_MODULE_DCSTAT_IDX))))
607 + continue;
608 +
609 + ebpf_dcstat_sum_pids(&w->dcstat, w->root_pid);
610 +
611 + uint64_t cache = w->dcstat.curr.cache_access;
612 + uint64_t not_found = w->dcstat.curr.not_found;
613 +
614 + dcstat_update_publish(&w->dcstat, cache, not_found);
615 + }
616 +}
617 +
618 +/**
619 + * DCstat thread
620 + *
621 + * Thread used to generate dcstat charts.
622 + *
623 + * @param ptr a pointer to `struct ebpf_module`
624 + *
625 + * @return It always return NULL
626 + */
627 +void *ebpf_read_dcstat_thread(void *ptr)
628 +{
629 + heartbeat_t hb;
630 + heartbeat_init(&hb);
631 +
632 + ebpf_module_t *em = (ebpf_module_t *)ptr;
633 +
634 + int maps_per_core = em->maps_per_core;
635 + int update_every = em->update_every;
636 +
637 + int counter = update_every - 1;
638 +
639 + uint32_t lifetime = em->lifetime;
640 + uint32_t running_time = 0;
641 + usec_t period = update_every * USEC_PER_SEC;
642 + int max_period = update_every * EBPF_CLEANUP_FACTOR;
643 + while (!ebpf_plugin_exit && running_time < lifetime) {
644 + (void)heartbeat_next(&hb, period);
645 + if (ebpf_plugin_exit || ++counter != update_every)
646 + continue;
647 +
648 + netdata_thread_disable_cancelability();
649 +
650 + pthread_mutex_lock(&collect_data_mutex);
651 + ebpf_read_dc_apps_table(maps_per_core, max_period);
652 + ebpf_dc_resume_apps_data();
653 + pthread_mutex_unlock(&collect_data_mutex);
654 +
655 + counter = 0;
656 +
657 + pthread_mutex_lock(&ebpf_exit_cleanup);
658 + if (running_time && !em->running_time)
659 + running_time = update_every;
660 + else
661 + running_time += update_every;
662 +
663 + em->running_time = running_time;
664 + pthread_mutex_unlock(&ebpf_exit_cleanup);
665 + netdata_thread_enable_cancelability();
666 + }
667 +
668 + return NULL;
669 +}
670 +
671 /**
672 * Create apps charts
673 *
@@ -582,94 +756,6 @@ void ebpf_dcstat_create_apps_charts(struct ebpf_module *em, void *ptr)
756 *
757 *****************************************************************/
758
585 -/**
586 - * Apps Accumulator
587 - *
588 - * Sum all values read from kernel and store in the first address.
589 - *
590 - * @param out the vector with read values.
591 - * @param maps_per_core do I need to read all cores?
592 - */
593 -static void dcstat_apps_accumulator(netdata_dcstat_pid_t *out, int maps_per_core)
594 -{
595 - int i, end = (maps_per_core) ? ebpf_nprocs : 1;
596 - netdata_dcstat_pid_t *total = &out[0];
597 - for (i = 1; i < end; i++) {
598 - netdata_dcstat_pid_t *w = &out[i];
599 - total->cache_access += w->cache_access;
600 - total->file_system += w->file_system;
601 - total->not_found += w->not_found;
602 - }
603 -}
604 -
605 -/**
606 - * Save PID values
607 - *
608 - * Save the current values inside the structure
609 - *
610 - * @param out vector used to plot charts
611 - * @param publish vector with values read from hash tables.
612 - */
613 -static inline void dcstat_save_pid_values(netdata_publish_dcstat_t *out, netdata_dcstat_pid_t *publish)
614 -{
615 - memcpy(&out->curr, &publish[0], sizeof(netdata_dcstat_pid_t));
616 -}
617 -
618 -/**
619 - * Fill PID
620 - *
621 - * Fill PID structures
622 - *
623 - * @param current_pid pid that we are collecting data
624 - * @param out values read from hash tables;
625 - */
626 -static void dcstat_fill_pid(uint32_t current_pid, netdata_dcstat_pid_t *publish)
627 -{
628 - netdata_publish_dcstat_t *curr = dcstat_pid[current_pid];
629 - if (!curr) {
630 - curr = ebpf_publish_dcstat_get();
631 - dcstat_pid[current_pid] = curr;
632 - }
633 -
634 - dcstat_save_pid_values(curr, publish);
635 -}
636 -
637 -/**
638 - * Read Directory Cache APPS table
639 - *
640 - * Read the apps table and store data inside the structure.
641 - *
642 - * @param maps_per_core do I need to read all cores?
643 - */
644 -static void read_dc_apps_table(int maps_per_core)
645 -{
646 - netdata_dcstat_pid_t *cv = dcstat_vector;
647 - uint32_t key;
648 - struct ebpf_pid_stat *pids = ebpf_root_of_pids;
649 - int fd = dcstat_maps[NETDATA_DCSTAT_PID_STATS].map_fd;
650 - size_t length = sizeof(netdata_dcstat_pid_t);
651 - if (maps_per_core)
652 - length *= ebpf_nprocs;
653 -
654 - while (pids) {
655 - key = pids->pid;
656 -
657 - if (bpf_map_lookup_elem(fd, &key, cv)) {
658 - pids = pids->next;
659 - continue;
660 - }
661 -
662 - dcstat_apps_accumulator(cv, maps_per_core);
663 -
664 - dcstat_fill_pid(key, cv);
665 -
666 - // We are cleaning to avoid passing data read from one process to other.
667 - memset(cv, 0, length);
668 -
669 - pids = pids->next;
670 - }
671 -}
672 -
759 /**
760 * Update cgroup
761 *
@@ -677,12 +763,8 @@ static void read_dc_apps_table(int maps_per_core)
763 *
764 * @param maps_per_core do I need to read all cores?
765 */
680 -static void ebpf_update_dc_cgroup(int maps_per_core)
766 +static void ebpf_update_dc_cgroup()
767 {
682 - netdata_dcstat_pid_t *cv = dcstat_vector;
683 - int fd = dcstat_maps[NETDATA_DCSTAT_PID_STATS].map_fd;
684 - size_t length = sizeof(netdata_dcstat_pid_t)*ebpf_nprocs;
685 -
768 ebpf_cgroup_target_t *ect;
769 pthread_mutex_lock(&mutex_cgroup_shm);
770 for (ect = ebpf_cgroup_pids; ect; ect = ect->next) {
@@ -690,19 +772,11 @@ static void ebpf_update_dc_cgroup(int maps_per_core)
772 for (pids = ect->pids; pids; pids = pids->next) {
773 int pid = pids->pid;
774 netdata_dcstat_pid_t *out = &pids->dc;
693 - if (likely(dcstat_pid) && dcstat_pid[pid]) {
694 - netdata_publish_dcstat_t *in = dcstat_pid[pid];
775 + ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(pid, 0);
776 + if (local_pid) {
777 + netdata_publish_dcstat_t *in = &local_pid->dc;
778
779 memcpy(out, &in->curr, sizeof(netdata_dcstat_pid_t));
697 - } else {
698 - memset(cv, 0, length);
699 - if (bpf_map_lookup_elem(fd, &pid, cv)) {
700 - continue;
701 - }
702 -
703 - dcstat_apps_accumulator(cv, maps_per_core);
704 -
705 - memcpy(out, cv, sizeof(netdata_dcstat_pid_t));
780 }
781 }
782 }
@@ -734,32 +808,6 @@ static void ebpf_dc_read_global_tables(netdata_idx_t *stats, int maps_per_core)
808 NETDATA_CONTROLLER_END);
809 }
810
737 -/**
738 - * Cachestat sum PIDs
739 - *
740 - * Sum values for all PIDs associated to a group
741 - *
742 - * @param publish output structure.
743 - * @param root structure with listed IPs
744 - */
745 -void ebpf_dcstat_sum_pids(netdata_publish_dcstat_t *publish, struct ebpf_pid_on_target *root)
746 -{
747 - memset(&publish->curr, 0, sizeof(netdata_dcstat_pid_t));
748 - netdata_dcstat_pid_t *dst = &publish->curr;
749 - while (root) {
750 - int32_t pid = root->pid;
751 - netdata_publish_dcstat_t *w = dcstat_pid[pid];
752 - if (w) {
753 - netdata_dcstat_pid_t *src = &w->curr;
754 - dst->cache_access += src->cache_access;
755 - dst->file_system += src->file_system;
756 - dst->not_found += src->not_found;
757 - }
758 -
759 - root = root->next;
760 - }
761 -}
762 -
811 /**
812 * Send data to Netdata calling auxiliary functions.
813 *
@@ -770,17 +818,11 @@ void ebpf_dcache_send_apps_data(struct ebpf_target *root)
818 struct ebpf_target *w;
819 collected_number value;
820
821 + pthread_mutex_lock(&collect_data_mutex);
822 for (w = root; w; w = w->next) {
823 if (unlikely(!(w->charts_created & (1<<EBPF_MODULE_DCSTAT_IDX))))
824 continue;
825
777 - ebpf_dcstat_sum_pids(&w->dcstat, w->root_pid);
778 -
779 - uint64_t cache = w->dcstat.curr.cache_access;
780 - uint64_t not_found = w->dcstat.curr.not_found;
781 -
782 - dcstat_update_publish(&w->dcstat, cache, not_found);
783 -
826 value = (collected_number) w->dcstat.ratio;
827 ebpf_write_begin_chart(NETDATA_APP_FAMILY, w->clean_name, "_ebpf_dc_hit");
828 write_chart_dimension("ratio", value);
@@ -817,6 +859,7 @@ void ebpf_dcache_send_apps_data(struct ebpf_target *root)
859 ebpf_write_end_chart();
860 w->dcstat.prev.not_found = w->dcstat.curr.not_found;
861 }
862 + pthread_mutex_unlock(&collect_data_mutex);
863 }
864
865 /**
@@ -1195,12 +1238,9 @@ static void dcstat_collector(ebpf_module_t *em)
1238 counter = 0;
1239 netdata_apps_integration_flags_t apps = em->apps_charts;
1240 ebpf_dc_read_global_tables(stats, maps_per_core);
1198 - pthread_mutex_lock(&collect_data_mutex);
1199 - if (apps)
1200 - read_dc_apps_table(maps_per_core);
1241
1242 if (cgroups)
1203 - ebpf_update_dc_cgroup(maps_per_core);
1243 + ebpf_update_dc_cgroup();
1244
1245 pthread_mutex_lock(&lock);
1246
@@ -1209,16 +1249,10 @@ static void dcstat_collector(ebpf_module_t *em)
1249 if (apps & NETDATA_EBPF_APPS_FLAG_CHART_CREATED)
1250 ebpf_dcache_send_apps_data(apps_groups_root_target);
1251
1212 -#ifdef NETDATA_DEV_MODE
1213 - if (ebpf_aral_dcstat_pid)
1214 - ebpf_send_data_aral_chart(ebpf_aral_dcstat_pid, em);
1215 -#endif
1216 -
1252 if (cgroups)
1253 ebpf_dc_send_cgroup_data(update_every);
1254
1255 pthread_mutex_unlock(&lock);
1221 - pthread_mutex_unlock(&collect_data_mutex);
1256
1257 pthread_mutex_lock(&ebpf_exit_cleanup);
1258 if (running_time && !em->running_time)
@@ -1273,17 +1307,10 @@ static void ebpf_create_dc_global_charts(int update_every)
1307 *
1308 * We are not testing the return, because callocz does this and shutdown the software
1309 * case it was not possible to allocate.
1276 - *
1277 - * @param apps is apps enabled?
1310 */
1279 -static void ebpf_dcstat_allocate_global_vectors(int apps)
1311 +static void ebpf_dcstat_allocate_global_vectors()
1312 {
1281 - if (apps) {
1282 - ebpf_dcstat_aral_init();
1283 - dcstat_pid = callocz((size_t)pid_max, sizeof(netdata_publish_dcstat_t *));
1284 - dcstat_vector = callocz((size_t)ebpf_nprocs, sizeof(netdata_dcstat_pid_t));
1285 - }
1286 -
1313 + dcstat_vector = callocz((size_t)ebpf_nprocs, sizeof(netdata_dcstat_pid_t));
1314 dcstat_values = callocz((size_t)ebpf_nprocs, sizeof(netdata_idx_t));
1315
1316 memset(dcstat_counter_aggregated_data, 0, NETDATA_DCSTAT_IDX_END * sizeof(netdata_syscall_stat_t));
@@ -1360,7 +1387,7 @@ void *ebpf_dcstat_thread(void *ptr)
1387 goto enddcstat;
1388 }
1389
1363 - ebpf_dcstat_allocate_global_vectors(em->apps_charts);
1390 + ebpf_dcstat_allocate_global_vectors();
1391
1392 int algorithms[NETDATA_DCSTAT_IDX_END] = {
1393 NETDATA_EBPF_ABSOLUTE_IDX, NETDATA_EBPF_ABSOLUTE_IDX, NETDATA_EBPF_ABSOLUTE_IDX,
@@ -1375,13 +1402,16 @@ void *ebpf_dcstat_thread(void *ptr)
1402 ebpf_create_dc_global_charts(em->update_every);
1403 ebpf_update_stats(&plugin_statistics, em);
1404 ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_ADD);
1378 -#ifdef NETDATA_DEV_MODE
1379 - if (ebpf_aral_dcstat_pid)
1380 - dcstat_disable_priority = ebpf_statistic_create_aral_chart(NETDATA_EBPF_DCSTAT_ARAL_NAME, em);
1381 -#endif
1405
1406 pthread_mutex_unlock(&lock);
1407
1408 + ebpf_read_dcstat.thread = mallocz(sizeof(netdata_thread_t));
1409 + netdata_thread_create(ebpf_read_dcstat.thread,
1410 + ebpf_read_dcstat.name,
1411 + NETDATA_THREAD_OPTION_DEFAULT,
1412 + ebpf_read_dcstat_thread,
1413 + em);
1414 +
1415 dcstat_collector(em);
1416
1417 enddcstat:
src/collectors/ebpf.plugin/ebpf_dcstat.h
+2
@@ -76,6 +76,8 @@ typedef struct netdata_publish_dcstat_pid {
76 } netdata_dcstat_pid_t;
77
78 typedef struct netdata_publish_dcstat {
79 + uint64_t ct;
80 +
81 long long ratio;
82 long long cache_access;
83
src/collectors/ebpf.plugin/ebpf_fd.c
+144 -113
@@ -57,9 +57,16 @@ 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
60 +struct netdata_static_thread ebpf_read_fd = {
61 + .name = "EBPF_READ_FD",
62 + .config_section = NULL,
63 + .config_name = NULL,
64 + .env_name = NULL,
65 + .enabled = 1,
66 + .thread = NULL,
67 + .init_routine = NULL,
68 + .start_routine = NULL
69 +};
70
71 #ifdef LIBBPF_MAJOR_VERSION
72 /**
@@ -174,7 +181,7 @@ static int ebpf_fd_attach_probe(struct fd_bpf *obj)
181 {
182 obj->links.netdata_sys_open_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_sys_open_kprobe, false,
183 fd_targets[NETDATA_FD_SYSCALL_OPEN].name);
177 - int ret = libbpf_get_error(obj->links.netdata_sys_open_kprobe);
184 + long ret = libbpf_get_error(obj->links.netdata_sys_open_kprobe);
185 if (ret)
186 return -1;
187
@@ -438,6 +445,7 @@ void ebpf_obsolete_fd_apps_charts(struct ebpf_module *em)
445 {
446 struct ebpf_target *w;
447 int update_every = em->update_every;
448 + pthread_mutex_lock(&collect_data_mutex);
449 for (w = apps_groups_root_target; w; w = w->next) {
450 if (unlikely(!(w->charts_created & (1<<EBPF_MODULE_FD_IDX))))
451 continue;
@@ -491,6 +499,7 @@ void ebpf_obsolete_fd_apps_charts(struct ebpf_module *em)
499 }
500 w->charts_created &= ~(1<<EBPF_MODULE_FD_IDX);
501 }
502 + pthread_mutex_unlock(&collect_data_mutex);
503 }
504
505 /**
@@ -538,6 +547,9 @@ static void ebpf_fd_exit(void *ptr)
547 {
548 ebpf_module_t *em = (ebpf_module_t *)ptr;
549
550 + if (ebpf_read_fd.thread)
551 + netdata_thread_cancel(*ebpf_read_fd.thread);
552 +
553 if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
554 pthread_mutex_lock(&lock);
555 if (em->cgroup_charts) {
@@ -551,12 +563,6 @@ static void ebpf_fd_exit(void *ptr)
563
564 ebpf_obsolete_fd_global(em);
565
554 -#ifdef NETDATA_DEV_MODE
555 - if (ebpf_aral_fd_pid)
556 - ebpf_statistic_obsolete_aral_chart(em, fd_disable_priority);
557 -#endif
558 -
559 -
566 fflush(stdout);
567 pthread_mutex_unlock(&lock);
568 }
@@ -655,25 +661,6 @@ static void fd_apps_accumulator(netdata_fd_stat_t *out, int maps_per_core)
661 }
662 }
663
658 -/**
659 - * Fill PID
660 - *
661 - * Fill PID structures
662 - *
663 - * @param current_pid pid that we are collecting data
664 - * @param out values read from hash tables;
665 - */
666 -static void fd_fill_pid(uint32_t current_pid, netdata_fd_stat_t *publish)
667 -{
668 - netdata_fd_stat_t *curr = fd_pid[current_pid];
669 - if (!curr) {
670 - curr = ebpf_fd_stat_get();
671 - fd_pid[current_pid] = curr;
672 - }
673 -
674 - memcpy(curr, &publish[0], sizeof(netdata_fd_stat_t));
675 -}
676 -
664 /**
665 * Read APPS table
666 *
@@ -681,33 +668,134 @@ static void fd_fill_pid(uint32_t current_pid, netdata_fd_stat_t *publish)
668 *
669 * @param maps_per_core do I need to read all cores?
670 */
684 -static void read_fd_apps_table(int maps_per_core)
671 +static void ebpf_read_fd_apps_table(int maps_per_core, int max_period)
672 {
673 netdata_fd_stat_t *fv = fd_vector;
687 - uint32_t key;
688 - struct ebpf_pid_stat *pids = ebpf_root_of_pids;
674 int fd = fd_maps[NETDATA_FD_PID_STATS].map_fd;
675 size_t length = sizeof(netdata_fd_stat_t);
676 if (maps_per_core)
677 length *= ebpf_nprocs;
678
694 - while (pids) {
695 - key = pids->pid;
696 -
679 + uint32_t key = 0, next_key = 0;
680 + while (bpf_map_get_next_key(fd, &key, &next_key) == 0) {
681 if (bpf_map_lookup_elem(fd, &key, fv)) {
698 - pids = pids->next;
699 - continue;
682 + goto end_fd_loop;
683 }
684
685 fd_apps_accumulator(fv, maps_per_core);
686
704 - fd_fill_pid(key, fv);
687 + ebpf_pid_stat_t *pid_stat = ebpf_get_pid_entry(key, fv->tgid);
688 + if (pid_stat) {
689 + netdata_fd_stat_t *publish_fd = &pid_stat->fd;
690 + if (!publish_fd->ct || publish_fd->ct != fv->ct) {
691 + memcpy(publish_fd, &fv[0], sizeof(netdata_fd_stat_t));
692 + pid_stat->not_updated = 0;
693 + } else if (++pid_stat->not_updated >= max_period) {
694 + bpf_map_delete_elem(fd, &key);
695 + pid_stat->not_updated = 0;
696 + }
697 + }
698
699 +end_fd_loop:
700 // We are cleaning to avoid passing data read from one process to other.
701 memset(fv, 0, length);
702 + key = next_key;
703 + }
704 +}
705
709 - pids = pids->next;
706 +/**
707 + * Sum PIDs
708 + *
709 + * Sum values for all targets.
710 + *
711 + * @param fd the output
712 + * @param root list of pids
713 + */
714 +static void ebpf_fd_sum_pids(netdata_fd_stat_t *fd, struct ebpf_pid_on_target *root)
715 +{
716 + memset(fd, 0, sizeof(netdata_fd_stat_t));
717 +
718 + while (root) {
719 + int32_t pid = root->pid;
720 + ebpf_pid_stat_t *pid_stat = ebpf_get_pid_entry(pid, 0);
721 + if (pid_stat) {
722 + netdata_fd_stat_t *w = &pid_stat->fd;
723 + fd->open_call += w->open_call;
724 + fd->close_call += w->close_call;
725 + fd->open_err += w->open_err;
726 + fd->close_err += w->close_err;
727 + }
728 +
729 + root = root->next;
730 + }
731 +}
732 +
733 +/**
734 + * Resume apps data
735 + */
736 +void ebpf_fd_resume_apps_data()
737 +{
738 + struct ebpf_target *w;
739 +
740 + for (w = apps_groups_root_target; w; w = w->next) {
741 + if (unlikely(!(w->charts_created & (1<<EBPF_MODULE_FD_IDX))))
742 + continue;
743 +
744 + ebpf_fd_sum_pids(&w->fd, w->root_pid);
745 + }
746 +}
747 +
748 +/**
749 + * DCstat thread
750 + *
751 + * Thread used to generate dcstat charts.
752 + *
753 + * @param ptr a pointer to `struct ebpf_module`
754 + *
755 + * @return It always return NULL
756 + */
757 +void *ebpf_read_fd_thread(void *ptr)
758 +{
759 + heartbeat_t hb;
760 + heartbeat_init(&hb);
761 +
762 + ebpf_module_t *em = (ebpf_module_t *)ptr;
763 +
764 + int maps_per_core = em->maps_per_core;
765 + int update_every = em->update_every;
766 +
767 + int counter = update_every - 1;
768 +
769 + uint32_t lifetime = em->lifetime;
770 + uint32_t running_time = 0;
771 + usec_t period = update_every * USEC_PER_SEC;
772 + int max_period = update_every * EBPF_CLEANUP_FACTOR;
773 + while (!ebpf_plugin_exit && running_time < lifetime) {
774 + (void)heartbeat_next(&hb, period);
775 + if (ebpf_plugin_exit || ++counter != update_every)
776 + continue;
777 +
778 + netdata_thread_disable_cancelability();
779 +
780 + pthread_mutex_lock(&collect_data_mutex);
781 + ebpf_read_fd_apps_table(maps_per_core, max_period);
782 + ebpf_fd_resume_apps_data();
783 + pthread_mutex_unlock(&collect_data_mutex);
784 +
785 + counter = 0;
786 +
787 + pthread_mutex_lock(&ebpf_exit_cleanup);
788 + if (running_time && !em->running_time)
789 + running_time = update_every;
790 + else
791 + running_time += update_every;
792 +
793 + em->running_time = running_time;
794 + pthread_mutex_unlock(&ebpf_exit_cleanup);
795 + netdata_thread_enable_cancelability();
796 }
797 +
798 + return NULL;
799 }
800
801 /**
@@ -717,12 +805,9 @@ static void read_fd_apps_table(int maps_per_core)
805 *
806 * @param maps_per_core do I need to read all cores?
807 */
720 -static void ebpf_update_fd_cgroup(int maps_per_core)
808 +static void ebpf_update_fd_cgroup()
809 {
810 ebpf_cgroup_target_t *ect ;
723 - netdata_fd_stat_t *fv = fd_vector;
724 - int fd = fd_maps[NETDATA_FD_PID_STATS].map_fd;
725 - size_t length = sizeof(netdata_fd_stat_t) * ebpf_nprocs;
811
812 pthread_mutex_lock(&mutex_cgroup_shm);
813 for (ect = ebpf_cgroup_pids; ect; ect = ect->next) {
@@ -730,58 +815,17 @@ static void ebpf_update_fd_cgroup(int maps_per_core)
815 for (pids = ect->pids; pids; pids = pids->next) {
816 int pid = pids->pid;
817 netdata_fd_stat_t *out = &pids->fd;
733 - if (likely(fd_pid) && fd_pid[pid]) {
734 - netdata_fd_stat_t *in = fd_pid[pid];
818 + ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(pid, 0);
819 + if (local_pid) {
820 + netdata_fd_stat_t *in = &local_pid->fd;
821
822 memcpy(out, in, sizeof(netdata_fd_stat_t));
737 - } else {
738 - memset(fv, 0, length);
739 - if (!bpf_map_lookup_elem(fd, &pid, fv)) {
740 - fd_apps_accumulator(fv, maps_per_core);
741 -
742 - memcpy(out, fv, sizeof(netdata_fd_stat_t));
743 - }
823 }
824 }
825 }
826 pthread_mutex_unlock(&mutex_cgroup_shm);
827 }
828
750 -/**
751 - * Sum PIDs
752 - *
753 - * Sum values for all targets.
754 - *
755 - * @param fd the output
756 - * @param root list of pids
757 - */
758 -static void ebpf_fd_sum_pids(netdata_fd_stat_t *fd, struct ebpf_pid_on_target *root)
759 -{
760 - uint32_t open_call = 0;
761 - uint32_t close_call = 0;
762 - uint32_t open_err = 0;
763 - uint32_t close_err = 0;
764 -
765 - while (root) {
766 - int32_t pid = root->pid;
767 - netdata_fd_stat_t *w = fd_pid[pid];
768 - if (w) {
769 - open_call += w->open_call;
770 - close_call += w->close_call;
771 - open_err += w->open_err;
772 - close_err += w->close_err;
773 - }
774 -
775 - root = root->next;
776 - }
777 -
778 - // These conditions were added, because we are using incremental algorithm
779 - fd->open_call = (open_call >= fd->open_call) ? open_call : fd->open_call;
780 - fd->close_call = (close_call >= fd->close_call) ? close_call : fd->close_call;
781 - fd->open_err = (open_err >= fd->open_err) ? open_err : fd->open_err;
782 - fd->close_err = (close_err >= fd->close_err) ? close_err : fd->close_err;
783 -}
784 -
829 /**
830 * Send data to Netdata calling auxiliary functions.
831 *
@@ -791,12 +835,11 @@ static void ebpf_fd_sum_pids(netdata_fd_stat_t *fd, struct ebpf_pid_on_target *r
835 void ebpf_fd_send_apps_data(ebpf_module_t *em, struct ebpf_target *root)
836 {
837 struct ebpf_target *w;
838 + pthread_mutex_lock(&collect_data_mutex);
839 for (w = root; w; w = w->next) {
840 if (unlikely(!(w->charts_created & (1<<EBPF_MODULE_FD_IDX))))
841 continue;
842
798 - ebpf_fd_sum_pids(&w->fd, w->root_pid);
799 -
843 ebpf_write_begin_chart(NETDATA_APP_FAMILY, w->clean_name, "_ebpf_file_open");
844 write_chart_dimension("calls", w->fd.open_call);
845 ebpf_write_end_chart();
@@ -817,6 +860,7 @@ void ebpf_fd_send_apps_data(ebpf_module_t *em, struct ebpf_target *root)
860 ebpf_write_end_chart();
861 }
862 }
863 + pthread_mutex_unlock(&collect_data_mutex);
864 }
865
866 /**
@@ -1120,20 +1164,12 @@ static void fd_collector(ebpf_module_t *em)
1164 counter = 0;
1165 netdata_apps_integration_flags_t apps = em->apps_charts;
1166 ebpf_fd_read_global_tables(stats, maps_per_core);
1123 - pthread_mutex_lock(&collect_data_mutex);
1124 - if (apps)
1125 - read_fd_apps_table(maps_per_core);
1167
1168 if (cgroups)
1128 - ebpf_update_fd_cgroup(maps_per_core);
1169 + ebpf_update_fd_cgroup();
1170
1171 pthread_mutex_lock(&lock);
1172
1132 -#ifdef NETDATA_DEV_MODE
1133 - if (ebpf_aral_fd_pid)
1134 - ebpf_send_data_aral_chart(ebpf_aral_fd_pid, em);
1135 -#endif
1136 -
1173 ebpf_fd_send_data(em);
1174
1175 if (apps & NETDATA_EBPF_APPS_FLAG_CHART_CREATED)
@@ -1143,7 +1179,6 @@ static void fd_collector(ebpf_module_t *em)
1179 ebpf_fd_send_cgroup_data(em);
1180
1181 pthread_mutex_unlock(&lock);
1146 - pthread_mutex_unlock(&collect_data_mutex);
1182
1183 pthread_mutex_lock(&ebpf_exit_cleanup);
1184 if (running_time && !em->running_time)
@@ -1299,17 +1334,10 @@ static void ebpf_create_fd_global_charts(ebpf_module_t *em)
1334 *
1335 * We are not testing the return, because callocz does this and shutdown the software
1336 * case it was not possible to allocate.
1302 - *
1303 - * @param apps is apps enabled?
1337 */
1305 -static void ebpf_fd_allocate_global_vectors(int apps)
1338 +static inline void ebpf_fd_allocate_global_vectors()
1339 {
1307 - if (apps) {
1308 - ebpf_fd_aral_init();
1309 - fd_pid = callocz((size_t)pid_max, sizeof(netdata_fd_stat_t *));
1310 - fd_vector = callocz((size_t)ebpf_nprocs, sizeof(netdata_fd_stat_t));
1311 - }
1312 -
1340 + fd_vector = callocz((size_t)ebpf_nprocs, sizeof(netdata_fd_stat_t));
1341 fd_values = callocz((size_t)ebpf_nprocs, sizeof(netdata_idx_t));
1342 }
1343
@@ -1373,7 +1401,7 @@ void *ebpf_fd_thread(void *ptr)
1401 goto endfd;
1402 }
1403
1376 - ebpf_fd_allocate_global_vectors(em->apps_charts);
1404 + ebpf_fd_allocate_global_vectors();
1405
1406 int algorithms[NETDATA_FD_SYSCALL_END] = {
1407 NETDATA_EBPF_INCREMENTAL_IDX, NETDATA_EBPF_INCREMENTAL_IDX
@@ -1386,13 +1414,16 @@ void *ebpf_fd_thread(void *ptr)
1414 ebpf_create_fd_global_charts(em);
1415 ebpf_update_stats(&plugin_statistics, em);
1416 ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_ADD);
1389 -#ifdef NETDATA_DEV_MODE
1390 - if (ebpf_aral_fd_pid)
1391 - fd_disable_priority = ebpf_statistic_create_aral_chart(NETDATA_EBPF_FD_ARAL_NAME, em);
1392 -#endif
1417
1418 pthread_mutex_unlock(&lock);
1419
1420 + ebpf_read_fd.thread = mallocz(sizeof(netdata_thread_t));
1421 + netdata_thread_create(ebpf_read_fd.thread,
1422 + ebpf_read_fd.name,
1423 + NETDATA_THREAD_OPTION_DEFAULT,
1424 + ebpf_read_fd_thread,
1425 + em);
1426 +
1427 fd_collector(em);
1428
1429 endfd:
src/collectors/ebpf.plugin/ebpf_oomkill.c
+4 -5
@@ -101,6 +101,7 @@ static void ebpf_obsolete_oomkill_apps(ebpf_module_t *em)
101 {
102 struct ebpf_target *w;
103 int update_every = em->update_every;
104 + pthread_mutex_lock(&collect_data_mutex);
105 for (w = apps_groups_root_target; w; w = w->next) {
106 if (unlikely(!(w->charts_created & (1<<EBPF_MODULE_OOMKILL_IDX))))
107 continue;
@@ -118,6 +119,7 @@ static void ebpf_obsolete_oomkill_apps(ebpf_module_t *em)
119
120 w->charts_created &= ~(1<<EBPF_MODULE_OOMKILL_IDX);
121 }
122 + pthread_mutex_unlock(&collect_data_mutex);
123 }
124
125 /**
@@ -443,14 +445,10 @@ static void oomkill_collector(ebpf_module_t *em)
445 counter = 0;
446
447 uint32_t count = oomkill_read_data(keys);
446 - if (!count) {
447 - running_time = ebpf_update_oomkill_period(running_time, em);
448 - }
448
449 stats[NETDATA_CONTROLLER_PID_TABLE_ADD] += (uint64_t) count;
450 stats[NETDATA_CONTROLLER_PID_TABLE_DEL] += (uint64_t) count;
451
453 - pthread_mutex_lock(&collect_data_mutex);
452 pthread_mutex_lock(&lock);
453 if (cgroups && count) {
454 ebpf_update_oomkill_cgroup(keys, count);
@@ -459,10 +457,11 @@ static void oomkill_collector(ebpf_module_t *em)
457 }
458
459 if (em->apps_charts & NETDATA_EBPF_APPS_FLAG_CHART_CREATED) {
460 + pthread_mutex_lock(&collect_data_mutex);
461 oomkill_write_data(keys, count);
462 + pthread_mutex_unlock(&collect_data_mutex);
463 }
464 pthread_mutex_unlock(&lock);
465 - pthread_mutex_unlock(&collect_data_mutex);
465
466 running_time = ebpf_update_oomkill_period(running_time, em);
467 }
src/collectors/ebpf.plugin/ebpf_process.c
+15 -110
@@ -65,10 +65,6 @@ struct config process_config = { .first_section = NULL,
65 .index = { .avl_tree = { .root = NULL, .compar = appconfig_section_compare },
66 .rwlock = AVL_LOCK_INITIALIZER } };
67
68 -#ifdef NETDATA_DEV_MODE
69 -int process_disable_priority;
70 -#endif
71 -
68 /*****************************************************************
69 *
70 * PROCESS DATA AND SEND TO NETDATA
@@ -146,53 +142,6 @@ static void ebpf_process_send_data(ebpf_module_t *em)
142 }
143 }
144
149 -/**
150 - * Sum values for pid
151 - *
152 - * @param root the structure with all available PIDs
153 - * @param offset the address that we are reading
154 - *
155 - * @return it returns the sum of all PIDs
156 - */
157 -long long ebpf_process_sum_values_for_pids(struct ebpf_pid_on_target *root, size_t offset)
158 -{
159 - long long ret = 0;
160 - while (root) {
161 - int32_t pid = root->pid;
162 - ebpf_process_stat_t *w = global_process_stats[pid];
163 - if (w) {
164 - uint32_t *value = (uint32_t *)((char *)w + offset);
165 - ret += *value;
166 - }
167 -
168 - root = root->next;
169 - }
170 -
171 - return ret;
172 -}
173 -
174 -/**
175 - * Remove process pid
176 - *
177 - * Remove from PID task table when task_release was called.
178 - */
179 -void ebpf_process_remove_pids()
180 -{
181 - struct ebpf_pid_stat *pids = ebpf_root_of_pids;
182 - int pid_fd = process_maps[NETDATA_PROCESS_PID_TABLE].map_fd;
183 - while (pids) {
184 - uint32_t pid = pids->pid;
185 - ebpf_process_stat_t *w = global_process_stats[pid];
186 - if (w) {
187 - ebpf_process_stat_release(w);
188 - global_process_stats[pid] = NULL;
189 - bpf_map_delete_elem(pid_fd, &pid);
190 - }
191 -
192 - pids = pids->next;
193 - }
194 -}
195 -
145 /**
146 * Send data to Netdata calling auxiliary functions.
147 *
@@ -201,46 +150,33 @@ void ebpf_process_remove_pids()
150 void ebpf_process_send_apps_data(struct ebpf_target *root, ebpf_module_t *em)
151 {
152 struct ebpf_target *w;
204 - // This algorithm is improved in https://github.com/netdata/netdata/pull/16030
205 - collected_number values[5];
153
154 for (w = root; w; w = w->next) {
155 if (unlikely(!(w->charts_created & (1<<EBPF_MODULE_PROCESS_IDX))))
156 continue;
157
211 - values[0] = ebpf_process_sum_values_for_pids(w->root_pid, offsetof(ebpf_process_stat_t, create_process));
212 - values[1] = ebpf_process_sum_values_for_pids(w->root_pid, offsetof(ebpf_process_stat_t, create_thread));
213 - values[2] = ebpf_process_sum_values_for_pids(w->root_pid, offsetof(ebpf_process_stat_t,
214 - exit_call));
215 - values[3] = ebpf_process_sum_values_for_pids(w->root_pid, offsetof(ebpf_process_stat_t,
216 - release_call));
217 - values[4] = ebpf_process_sum_values_for_pids(w->root_pid, offsetof(ebpf_process_stat_t,
218 - task_err));
219 -
158 ebpf_write_begin_chart(NETDATA_APP_FAMILY, w->clean_name, "_ebpf_process_start");
221 - write_chart_dimension("calls", values[0]);
159 + write_chart_dimension("calls", w->process.create_process);
160 ebpf_write_end_chart();
161
162 ebpf_write_begin_chart(NETDATA_APP_FAMILY, w->clean_name, "_ebpf_thread_start");
225 - write_chart_dimension("calls", values[1]);
163 + write_chart_dimension("calls", w->process.create_thread);
164 ebpf_write_end_chart();
165
166 ebpf_write_begin_chart(NETDATA_APP_FAMILY, w->clean_name, "_ebpf_task_exit");
229 - write_chart_dimension("calls", values[2]);
167 + write_chart_dimension("calls", w->process.exit_call);
168 ebpf_write_end_chart();
169
170 ebpf_write_begin_chart(NETDATA_APP_FAMILY, w->clean_name, "_ebpf_task_released");
233 - write_chart_dimension("calls", values[3]);
171 + write_chart_dimension("calls", w->process.release_call);
172 ebpf_write_end_chart();
173
174 if (em->mode < MODE_ENTRY) {
175 ebpf_write_begin_chart(NETDATA_APP_FAMILY, w->clean_name, "_ebpf_task_error");
238 - write_chart_dimension("calls", values[4]);
176 + write_chart_dimension("calls", w->process.task_err);
177 ebpf_write_end_chart();
178 }
179 }
242 -
243 - ebpf_process_remove_pids();
180 }
181
182 /*****************************************************************
@@ -287,34 +223,20 @@ static void ebpf_read_process_hash_global_tables(netdata_idx_t *stats, int maps_
223 *
224 * @param maps_per_core do I need to read all cores?
225 */
290 -static void ebpf_update_process_cgroup(int maps_per_core)
226 +static void ebpf_update_process_cgroup()
227 {
228 ebpf_cgroup_target_t *ect ;
293 - int pid_fd = process_maps[NETDATA_PROCESS_PID_TABLE].map_fd;
294 -
295 - size_t length = sizeof(ebpf_process_stat_t);
296 - if (maps_per_core)
297 - length *= ebpf_nprocs;
229 pthread_mutex_lock(&mutex_cgroup_shm);
230 for (ect = ebpf_cgroup_pids; ect; ect = ect->next) {
231 struct pid_on_target2 *pids;
232 for (pids = ect->pids; pids; pids = pids->next) {
233 int pid = pids->pid;
234 ebpf_process_stat_t *out = &pids->ps;
304 - if (global_process_stats[pid]) {
305 - ebpf_process_stat_t *in = global_process_stats[pid];
235 + ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(pid, 0);
236 + if (local_pid) {
237 + ebpf_process_stat_t *in = &local_pid->process;
238
239 memcpy(out, in, sizeof(ebpf_process_stat_t));
308 - } else {
309 - if (bpf_map_lookup_elem(pid_fd, &pid, process_stat_vector)) {
310 - memset(out, 0, sizeof(ebpf_process_stat_t));
311 - }
312 -
313 - ebpf_process_apps_accumulator(process_stat_vector, maps_per_core);
314 -
315 - memcpy(out, process_stat_vector, sizeof(ebpf_process_stat_t));
316 -
317 - memset(process_stat_vector, 0, length);
240 }
241 }
242 }
@@ -439,7 +361,7 @@ void ebpf_process_create_apps_charts(struct ebpf_module *em, void *ptr)
361 NETDATA_EBPF_MODULE_NAME_PROCESS);
362 ebpf_create_chart_labels("app_group", w->name, 1);
363 ebpf_commit_label();
442 - fprintf(stdout, "DIMENSION calls '' %s 1 1\n", ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
364 + fprintf(stdout, "DIMENSION calls '' %s 1 1\n", ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX]);
365
366 ebpf_write_chart_cmd(NETDATA_APP_FAMILY,
367 w->clean_name,
@@ -454,7 +376,7 @@ void ebpf_process_create_apps_charts(struct ebpf_module *em, void *ptr)
376 NETDATA_EBPF_MODULE_NAME_PROCESS);
377 ebpf_create_chart_labels("app_group", w->name, 1);
378 ebpf_commit_label();
457 - fprintf(stdout, "DIMENSION calls '' %s 1 1\n", ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
379 + fprintf(stdout, "DIMENSION calls '' %s 1 1\n", ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX]);
380
381 ebpf_write_chart_cmd(NETDATA_APP_FAMILY,
382 w->clean_name,
@@ -469,7 +391,7 @@ void ebpf_process_create_apps_charts(struct ebpf_module *em, void *ptr)
391 NETDATA_EBPF_MODULE_NAME_PROCESS);
392 ebpf_create_chart_labels("app_group", w->name, 1);
393 ebpf_commit_label();
472 - fprintf(stdout, "DIMENSION calls '' %s 1 1\n", ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
394 + fprintf(stdout, "DIMENSION calls '' %s 1 1\n", ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX]);
395
396 ebpf_write_chart_cmd(NETDATA_APP_FAMILY,
397 w->clean_name,
@@ -484,7 +406,7 @@ void ebpf_process_create_apps_charts(struct ebpf_module *em, void *ptr)
406 NETDATA_EBPF_MODULE_NAME_PROCESS);
407 ebpf_create_chart_labels("app_group", w->name, 1);
408 ebpf_commit_label();
487 - fprintf(stdout, "DIMENSION calls '' %s 1 1\n", ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
409 + fprintf(stdout, "DIMENSION calls '' %s 1 1\n", ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX]);
410
411 if (em->mode < MODE_ENTRY) {
412 ebpf_write_chart_cmd(NETDATA_APP_FAMILY,
@@ -500,7 +422,7 @@ void ebpf_process_create_apps_charts(struct ebpf_module *em, void *ptr)
422 NETDATA_EBPF_MODULE_NAME_PROCESS);
423 ebpf_create_chart_labels("app_group", w->name, 1);
424 ebpf_commit_label();
503 - fprintf(stdout, "DIMENSION calls '' %s 1 1\n", ebpf_algorithms[NETDATA_EBPF_ABSOLUTE_IDX]);
425 + fprintf(stdout, "DIMENSION calls '' %s 1 1\n", ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX]);
426 }
427 w->charts_created |= 1<<EBPF_MODULE_PROCESS_IDX;
428 }
@@ -785,11 +707,6 @@ static void ebpf_process_exit(void *ptr)
707
708 ebpf_obsolete_process_global(em);
709
788 -#ifdef NETDATA_DEV_MODE
789 - if (ebpf_aral_process_stat)
790 - ebpf_statistic_obsolete_aral_chart(em, process_disable_priority);
791 -#endif
792 -
710 fflush(stdout);
711 pthread_mutex_unlock(&lock);
712 }
@@ -1181,7 +1098,7 @@ static void process_collector(ebpf_module_t *em)
1098
1099 if (ebpf_all_pids_count > 0) {
1100 if (cgroups && shm_ebpf_cgroup.header) {
1184 - ebpf_update_process_cgroup(maps_per_core);
1101 + ebpf_update_process_cgroup();
1102 }
1103 }
1104
@@ -1195,11 +1112,6 @@ static void process_collector(ebpf_module_t *em)
1112 ebpf_process_send_apps_data(apps_groups_root_target, em);
1113 }
1114
1198 -#ifdef NETDATA_DEV_MODE
1199 - if (ebpf_aral_process_stat)
1200 - ebpf_send_data_aral_chart(ebpf_aral_process_stat, em);
1201 -#endif
1202 -
1115 if (cgroups && shm_ebpf_cgroup.header) {
1116 ebpf_process_send_cgroup_data(em);
1117 }
@@ -1240,8 +1152,6 @@ static void ebpf_process_allocate_global_vectors(size_t length)
1152 memset(process_publish_aggregated, 0, length * sizeof(netdata_publish_syscall_t));
1153 process_hash_values = callocz(ebpf_nprocs, sizeof(netdata_idx_t));
1154 process_stat_vector = callocz(ebpf_nprocs, sizeof(ebpf_process_stat_t));
1243 -
1244 - global_process_stats = callocz((size_t)pid_max, sizeof(ebpf_process_stat_t *));
1155 }
1156
1157 static void change_syscalls()
@@ -1351,11 +1261,6 @@ void *ebpf_process_thread(void *ptr)
1261 ebpf_update_stats(&plugin_statistics, em);
1262 ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_ADD);
1263
1354 -#ifdef NETDATA_DEV_MODE
1355 - if (ebpf_aral_process_stat)
1356 - process_disable_priority = ebpf_statistic_create_aral_chart(NETDATA_EBPF_PROC_ARAL_NAME, em);
1357 -#endif
1358 -
1264 pthread_mutex_unlock(&lock);
1265
1266 process_collector(em);
src/collectors/ebpf.plugin/ebpf_shm.c
+125 -82
@@ -54,6 +54,17 @@ netdata_ebpf_targets_t shm_targets[] = { {.name = "shmget", .mode = EBPF_LOAD_TR
54 int shm_disable_priority;
55 #endif
56
57 +struct netdata_static_thread ebpf_read_shm = {
58 + .name = "EBPF_READ_SHM",
59 + .config_section = NULL,
60 + .config_name = NULL,
61 + .env_name = NULL,
62 + .enabled = 1,
63 + .thread = NULL,
64 + .init_routine = NULL,
65 + .start_routine = NULL
66 +};
67 +
68 #ifdef LIBBPF_MAJOR_VERSION
69 /*****************************************************************
70 *
@@ -155,7 +166,7 @@ static int ebpf_shm_attach_probe(struct shm_bpf *obj)
166
167 obj->links.netdata_shmget_probe = bpf_program__attach_kprobe(obj->progs.netdata_shmget_probe,
168 false, syscall);
158 - int ret = (int)libbpf_get_error(obj->links.netdata_shmget_probe);
169 + long ret = libbpf_get_error(obj->links.netdata_shmget_probe);
170 if (ret)
171 return -1;
172
@@ -163,7 +174,7 @@ static int ebpf_shm_attach_probe(struct shm_bpf *obj)
174 shm_targets[NETDATA_KEY_SHMAT_CALL].name, running_on_kernel);
175 obj->links.netdata_shmat_probe = bpf_program__attach_kprobe(obj->progs.netdata_shmat_probe,
176 false, syscall);
166 - ret = (int)libbpf_get_error(obj->links.netdata_shmat_probe);
177 + ret = libbpf_get_error(obj->links.netdata_shmat_probe);
178 if (ret)
179 return -1;
180
@@ -171,7 +182,7 @@ static int ebpf_shm_attach_probe(struct shm_bpf *obj)
182 shm_targets[NETDATA_KEY_SHMDT_CALL].name, running_on_kernel);
183 obj->links.netdata_shmdt_probe = bpf_program__attach_kprobe(obj->progs.netdata_shmdt_probe,
184 false, syscall);
174 - ret = (int)libbpf_get_error(obj->links.netdata_shmdt_probe);
185 + ret = libbpf_get_error(obj->links.netdata_shmdt_probe);
186 if (ret)
187 return -1;
188
@@ -179,7 +190,7 @@ static int ebpf_shm_attach_probe(struct shm_bpf *obj)
190 shm_targets[NETDATA_KEY_SHMCTL_CALL].name, running_on_kernel);
191 obj->links.netdata_shmctl_probe = bpf_program__attach_kprobe(obj->progs.netdata_shmctl_probe,
192 false, syscall);
182 - ret = (int)libbpf_get_error(obj->links.netdata_shmctl_probe);
193 + ret = libbpf_get_error(obj->links.netdata_shmctl_probe);
194 if (ret)
195 return -1;
196
@@ -354,6 +365,7 @@ void ebpf_obsolete_shm_apps_charts(struct ebpf_module *em)
365 {
366 struct ebpf_target *w;
367 int update_every = em->update_every;
368 + pthread_mutex_lock(&collect_data_mutex);
369 for (w = apps_groups_root_target; w; w = w->next) {
370 if (unlikely(!(w->charts_created & (1<<EBPF_MODULE_SHM_IDX))))
371 continue;
@@ -404,6 +416,7 @@ void ebpf_obsolete_shm_apps_charts(struct ebpf_module *em)
416
417 w->charts_created &= ~(1<<EBPF_MODULE_SHM_IDX);
418 }
419 + pthread_mutex_unlock(&collect_data_mutex);
420 }
421
422 /**
@@ -438,6 +451,9 @@ static void ebpf_shm_exit(void *ptr)
451 {
452 ebpf_module_t *em = (ebpf_module_t *)ptr;
453
454 + if (ebpf_read_shm.thread)
455 + netdata_thread_cancel(*ebpf_read_shm.thread);
456 +
457 if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
458 pthread_mutex_lock(&lock);
459 if (em->cgroup_charts) {
@@ -451,11 +467,6 @@ static void ebpf_shm_exit(void *ptr)
467
468 ebpf_obsolete_shm_global(em);
469
454 -#ifdef NETDATA_DEV_MODE
455 - if (ebpf_aral_shm_pid)
456 - ebpf_statistic_obsolete_aral_chart(em, shm_disable_priority);
457 -#endif
458 -
470 fflush(stdout);
471 pthread_mutex_unlock(&lock);
472 }
@@ -506,25 +517,6 @@ static void shm_apps_accumulator(netdata_publish_shm_t *out, int maps_per_core)
517 }
518 }
519
509 -/**
510 - * Fill PID
511 - *
512 - * Fill PID structures
513 - *
514 - * @param current_pid pid that we are collecting data
515 - * @param out values read from hash tables;
516 - */
517 -static void shm_fill_pid(uint32_t current_pid, netdata_publish_shm_t *publish)
518 -{
519 - netdata_publish_shm_t *curr = shm_pid[current_pid];
520 - if (!curr) {
521 - curr = ebpf_shm_stat_get( );
522 - shm_pid[current_pid] = curr;
523 - }
524 -
525 - memcpy(curr, publish, sizeof(netdata_publish_shm_t));
526 -}
527 -
520 /**
521 * Update cgroup
522 *
@@ -532,13 +524,10 @@ static void shm_fill_pid(uint32_t current_pid, netdata_publish_shm_t *publish)
524 *
525 * @param maps_per_core do I need to read all cores?
526 */
535 -static void ebpf_update_shm_cgroup(int maps_per_core)
527 +static void ebpf_update_shm_cgroup()
528 {
529 netdata_publish_shm_t *cv = shm_vector;
538 - int fd = shm_maps[NETDATA_PID_SHM_TABLE].map_fd;
530 size_t length = sizeof(netdata_publish_shm_t);
540 - if (maps_per_core)
541 - length *= ebpf_nprocs;
531
532 ebpf_cgroup_target_t *ect;
533
@@ -550,20 +539,11 @@ static void ebpf_update_shm_cgroup(int maps_per_core)
539 for (pids = ect->pids; pids; pids = pids->next) {
540 int pid = pids->pid;
541 netdata_publish_shm_t *out = &pids->shm;
553 - if (likely(shm_pid) && shm_pid[pid]) {
554 - netdata_publish_shm_t *in = shm_pid[pid];
542 + ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(pid, 0);
543 + if (local_pid) {
544 + netdata_publish_shm_t *in = &local_pid->shm;
545
546 memcpy(out, in, sizeof(netdata_publish_shm_t));
557 - } else {
558 - if (!bpf_map_lookup_elem(fd, &pid, cv)) {
559 - shm_apps_accumulator(cv, maps_per_core);
560 -
561 - memcpy(out, cv, sizeof(netdata_publish_shm_t));
562 -
563 - // now that we've consumed the value, zero it out in the map.
564 - memset(cv, 0, length);
565 - bpf_map_update_elem(fd, &pid, cv, BPF_EXIST);
566 - }
547 }
548 }
549 }
@@ -577,33 +557,42 @@ static void ebpf_update_shm_cgroup(int maps_per_core)
557 *
558 * @param maps_per_core do I need to read all cores?
559 */
580 -static void read_shm_apps_table(int maps_per_core)
560 +static void ebpf_read_shm_apps_table(int maps_per_core, int max_period)
561 {
562 netdata_publish_shm_t *cv = shm_vector;
583 - uint32_t key;
584 - struct ebpf_pid_stat *pids = ebpf_root_of_pids;
563 int fd = shm_maps[NETDATA_PID_SHM_TABLE].map_fd;
564 size_t length = sizeof(netdata_publish_shm_t);
565 if (maps_per_core)
566 length *= ebpf_nprocs;
567
590 - while (pids) {
591 - key = pids->pid;
592 -
568 + uint32_t key = 0, next_key = 0;
569 + while (bpf_map_get_next_key(fd, &key, &next_key) == 0) {
570 if (bpf_map_lookup_elem(fd, &key, cv)) {
594 - pids = pids->next;
595 - continue;
571 + goto end_shm_loop;
572 }
573
574 shm_apps_accumulator(cv, maps_per_core);
575
600 - shm_fill_pid(key, cv);
576 + ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(key, 0);
577 + if (!local_pid)
578 + goto end_shm_loop;
579 +
580 +
581 + netdata_publish_shm_t *publish = &local_pid->shm;
582 + if (!publish->ct || publish->ct != cv->ct) {
583 + memcpy(publish, &cv[0], sizeof(netdata_publish_shm_t));
584 + local_pid->not_updated = 0;
585 + } else if (++local_pid->not_updated >= max_period){
586 + bpf_map_delete_elem(fd, &key);
587 + local_pid->not_updated = 0;
588 + }
589
590 +end_shm_loop:
591 // now that we've consumed the value, zero it out in the map.
592 memset(cv, 0, length);
593 bpf_map_update_elem(fd, &key, cv, BPF_EXIST);
594
606 - pids = pids->next;
595 + key = next_key;
596 }
597 }
598
@@ -662,10 +651,12 @@ static void ebpf_shm_read_global_table(netdata_idx_t *stats, int maps_per_core)
651 */
652 static void ebpf_shm_sum_pids(netdata_publish_shm_t *shm, struct ebpf_pid_on_target *root)
653 {
654 + memset(shm, 0, sizeof(netdata_publish_shm_t));
655 while (root) {
656 int32_t pid = root->pid;
667 - netdata_publish_shm_t *w = shm_pid[pid];
668 - if (w) {
657 + ebpf_pid_stat_t *pid_stat = ebpf_get_pid_entry(pid, 0);
658 + if (pid_stat) {
659 + netdata_publish_shm_t *w = &pid_stat->shm;
660 shm->get += w->get;
661 shm->at += w->at;
662 shm->dt += w->dt;
@@ -689,12 +680,11 @@ static void ebpf_shm_sum_pids(netdata_publish_shm_t *shm, struct ebpf_pid_on_tar
680 void ebpf_shm_send_apps_data(struct ebpf_target *root)
681 {
682 struct ebpf_target *w;
683 + pthread_mutex_lock(&collect_data_mutex);
684 for (w = root; w; w = w->next) {
685 if (unlikely(!(w->charts_created & (1<<EBPF_MODULE_SHM_IDX))))
686 continue;
687
696 - ebpf_shm_sum_pids(&w->shm, w->root_pid);
697 -
688 ebpf_write_begin_chart(NETDATA_APP_FAMILY, w->clean_name, "_ebpf_shmget_call");
689 write_chart_dimension("calls", (long long) w->shm.get);
690 ebpf_write_end_chart();
@@ -711,6 +701,7 @@ void ebpf_shm_send_apps_data(struct ebpf_target *root)
701 write_chart_dimension("calls", (long long) w->shm.ctl);
702 ebpf_write_end_chart();
703 }
704 + pthread_mutex_unlock(&collect_data_mutex);
705 }
706
707 /**
@@ -1000,6 +991,72 @@ void ebpf_shm_send_cgroup_data(int update_every)
991 pthread_mutex_unlock(&mutex_cgroup_shm);
992 }
993
994 +/**
995 + * Resume apps data
996 + */
997 +void ebpf_shm_resume_apps_data() {
998 + struct ebpf_target *w;
999 + for (w = apps_groups_root_target; w; w = w->next) {
1000 + if (unlikely(!(w->charts_created & (1 << EBPF_MODULE_SHM_IDX))))
1001 + continue;
1002 +
1003 + ebpf_shm_sum_pids(&w->shm, w->root_pid);
1004 + }
1005 +}
1006 +
1007 +/**
1008 + * DCstat thread
1009 + *
1010 + * Thread used to generate dcstat charts.
1011 + *
1012 + * @param ptr a pointer to `struct ebpf_module`
1013 + *
1014 + * @return It always return NULL
1015 + */
1016 +void *ebpf_read_shm_thread(void *ptr)
1017 +{
1018 + heartbeat_t hb;
1019 + heartbeat_init(&hb);
1020 +
1021 + ebpf_module_t *em = (ebpf_module_t *)ptr;
1022 +
1023 + int maps_per_core = em->maps_per_core;
1024 + int update_every = em->update_every;
1025 +
1026 + int counter = update_every - 1;
1027 +
1028 + uint32_t lifetime = em->lifetime;
1029 + uint32_t running_time = 0;
1030 + usec_t period = update_every * USEC_PER_SEC;
1031 + int max_period = update_every * EBPF_CLEANUP_FACTOR;
1032 + while (!ebpf_plugin_exit && running_time < lifetime) {
1033 + (void)heartbeat_next(&hb, period);
1034 + if (ebpf_plugin_exit || ++counter != update_every)
1035 + continue;
1036 +
1037 + netdata_thread_disable_cancelability();
1038 +
1039 + pthread_mutex_lock(&collect_data_mutex);
1040 + ebpf_read_shm_apps_table(maps_per_core, max_period);
1041 + ebpf_shm_resume_apps_data();
1042 + pthread_mutex_unlock(&collect_data_mutex);
1043 +
1044 + counter = 0;
1045 +
1046 + pthread_mutex_lock(&ebpf_exit_cleanup);
1047 + if (running_time && !em->running_time)
1048 + running_time = update_every;
1049 + else
1050 + running_time += update_every;
1051 +
1052 + em->running_time = running_time;
1053 + pthread_mutex_unlock(&ebpf_exit_cleanup);
1054 + netdata_thread_enable_cancelability();
1055 + }
1056 +
1057 + return NULL;
1058 +}
1059 +
1060 /**
1061 * Main loop for this collector.
1062 */
@@ -1023,34 +1080,23 @@ static void shm_collector(ebpf_module_t *em)
1080 counter = 0;
1081 netdata_apps_integration_flags_t apps = em->apps_charts;
1082 ebpf_shm_read_global_table(stats, maps_per_core);
1026 - pthread_mutex_lock(&collect_data_mutex);
1027 - if (apps) {
1028 - read_shm_apps_table(maps_per_core);
1029 - }
1083 + pthread_mutex_lock(&lock);
1084
1085 if (cgroups) {
1032 - ebpf_update_shm_cgroup(maps_per_core);
1086 + ebpf_update_shm_cgroup();
1087 }
1088
1035 - pthread_mutex_lock(&lock);
1036 -
1089 shm_send_global();
1090
1091 if (apps & NETDATA_EBPF_APPS_FLAG_CHART_CREATED) {
1092 ebpf_shm_send_apps_data(apps_groups_root_target);
1093 }
1094
1043 -#ifdef NETDATA_DEV_MODE
1044 - if (ebpf_aral_shm_pid)
1045 - ebpf_send_data_aral_chart(ebpf_aral_shm_pid, em);
1046 -#endif
1047 -
1095 if (cgroups) {
1096 ebpf_shm_send_cgroup_data(update_every);
1097 }
1098
1099 pthread_mutex_unlock(&lock);
1053 - pthread_mutex_unlock(&collect_data_mutex);
1100
1101 pthread_mutex_lock(&ebpf_exit_cleanup);
1102 if (running_time && !em->running_time)
@@ -1159,12 +1205,7 @@ void ebpf_shm_create_apps_charts(struct ebpf_module *em, void *ptr)
1205 */
1206 static void ebpf_shm_allocate_global_vectors(int apps)
1207 {
1162 - if (apps) {
1163 - ebpf_shm_aral_init();
1164 - shm_pid = callocz((size_t)pid_max, sizeof(netdata_publish_shm_t *));
1165 - shm_vector = callocz((size_t)ebpf_nprocs, sizeof(netdata_publish_shm_t));
1166 - }
1167 -
1208 + shm_vector = callocz((size_t)ebpf_nprocs, sizeof(netdata_publish_shm_t));
1209 shm_values = callocz((size_t)ebpf_nprocs, sizeof(netdata_idx_t));
1210
1211 memset(shm_hash_values, 0, sizeof(shm_hash_values));
@@ -1283,13 +1324,15 @@ void *ebpf_shm_thread(void *ptr)
1324 ebpf_create_shm_charts(em->update_every);
1325 ebpf_update_stats(&plugin_statistics, em);
1326 ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_ADD);
1286 -#ifdef NETDATA_DEV_MODE
1287 - if (ebpf_aral_shm_pid)
1288 - shm_disable_priority = ebpf_statistic_create_aral_chart(NETDATA_EBPF_SHM_ARAL_NAME, em);
1289 -#endif
1290 -
1327 pthread_mutex_unlock(&lock);
1328
1329 + ebpf_read_shm.thread = mallocz(sizeof(netdata_thread_t));
1330 + netdata_thread_create(ebpf_read_shm.thread,
1331 + ebpf_read_shm.name,
1332 + NETDATA_THREAD_OPTION_DEFAULT,
1333 + ebpf_read_shm_thread,
1334 + em);
1335 +
1336 shm_collector(em);
1337
1338 endshm:
src/collectors/ebpf.plugin/ebpf_shm.h
-3
@@ -28,9 +28,6 @@
28 #define NETDATA_SYSTEMD_SHM_DT_CONTEXT "services.shmdt"
29 #define NETDATA_SYSTEMD_SHM_CTL_CONTEXT "services.shmctl"
30
31 -// ARAL name
32 -#define NETDATA_EBPF_SHM_ARAL_NAME "ebpf_shm"
33 -
31 typedef struct netdata_publish_shm {
32 uint64_t ct;
33 char name[TASK_COMM_LEN];
src/collectors/ebpf.plugin/ebpf_socket.c
+75 -83
@@ -107,10 +107,6 @@ struct netdata_static_thread ebpf_read_socket = {
107
108 ARAL *aral_socket_table = NULL;
109
110 -#ifdef NETDATA_DEV_MODE
111 -int socket_disable_priority;
112 -#endif
113 -
110 #ifdef LIBBPF_MAJOR_VERSION
111 /**
112 * Disable Probe
@@ -650,6 +646,7 @@ void ebpf_socket_obsolete_apps_charts(struct ebpf_module *em)
646 int order = 20130;
647 struct ebpf_target *w;
648 int update_every = em->update_every;
649 + pthread_mutex_lock(&collect_data_mutex);
650 for (w = apps_groups_root_target; w; w = w->next) {
651 if (unlikely(!(w->charts_created & (1<<EBPF_MODULE_SOCKET_IDX))))
652 continue;
@@ -757,6 +754,7 @@ void ebpf_socket_obsolete_apps_charts(struct ebpf_module *em)
754
755 w->charts_created &= ~(1<<EBPF_MODULE_SOCKET_IDX);
756 }
757 + pthread_mutex_unlock(&collect_data_mutex);
758 }
759
760 /**
@@ -904,10 +902,6 @@ static void ebpf_socket_exit(void *ptr)
902
903 ebpf_socket_obsolete_global_charts(em);
904
907 -#ifdef NETDATA_DEV_MODE
908 - if (ebpf_aral_socket_pid)
909 - ebpf_statistic_obsolete_aral_chart(em, socket_disable_priority);
910 -#endif
905 pthread_mutex_unlock(&lock);
906 }
907
@@ -1031,83 +1025,57 @@ static void ebpf_socket_send_data(ebpf_module_t *em)
1025
1026 /**
1027 * Send data to Netdata calling auxiliary functions.
1034 - *
1035 - * @param em the structure with thread information
1036 - * @param root the target list.
1028 */
1038 -void ebpf_socket_send_apps_data(ebpf_module_t *em, struct ebpf_target *root)
1029 +void ebpf_socket_send_apps_data()
1030 {
1040 - UNUSED(em);
1041 -
1031 struct ebpf_target *w;
1043 - // This algorithm is improved in https://github.com/netdata/netdata/pull/16030
1044 - collected_number values[9];
1045 -
1046 - for (w = root; w; w = w->next) {
1032 + pthread_mutex_lock(&collect_data_mutex);
1033 + for (w = apps_groups_root_target; w; w = w->next) {
1034 if (unlikely(!(w->charts_created & (1<<EBPF_MODULE_SOCKET_IDX))))
1035 continue;
1036
1050 - struct ebpf_pid_on_target *move = w->root_pid;
1051 - // Simplify algorithm, but others will appear only in https://github.com/netdata/netdata/pull/16030
1052 - memset(values, 0, sizeof(values));
1053 - while (move) {
1054 - int32_t pid = move->pid;
1055 - ebpf_socket_publish_apps_t *ws = socket_bandwidth_curr[pid];
1056 - if (ws) {
1057 - values[0] += (collected_number) ws->call_tcp_v4_connection;
1058 - values[1] += (collected_number) ws->call_tcp_v6_connection;
1059 - values[2] += (collected_number) ws->bytes_sent;
1060 - values[3] += (collected_number) ws->bytes_received;
1061 - values[4] += (collected_number) ws->call_tcp_sent;
1062 - values[5] += (collected_number) ws->call_tcp_received;
1063 - values[6] += (collected_number) ws->retransmit;
1064 - values[7] += (collected_number) ws->call_udp_sent;
1065 - values[8] += (collected_number) ws->call_udp_received;
1066 - }
1067 -
1068 - move = move->next;
1069 - }
1070 -
1037 + ebpf_socket_publish_apps_t *values = &w->socket;
1038 ebpf_write_begin_chart(NETDATA_APP_FAMILY, w->clean_name, "_ebpf_call_tcp_v4_connection");
1072 - write_chart_dimension("connections", values[0]);
1039 + write_chart_dimension("connections", (collected_number) values->call_tcp_v4_connection);
1040 ebpf_write_end_chart();
1041
1042 if (tcp_v6_connect_address.type == 'T') {
1043 ebpf_write_begin_chart(NETDATA_APP_FAMILY, w->clean_name, "_call_tcp_v6_connection");
1077 - write_chart_dimension("calls", values[1]);
1044 + write_chart_dimension("calls", (collected_number) values->call_tcp_v6_connection);
1045 ebpf_write_end_chart();
1046 }
1047
1048 ebpf_write_begin_chart(NETDATA_APP_FAMILY, w->clean_name, "_ebpf_sock_bytes_sent");
1049 // We multiply by 0.008, because we read bytes, but we display bits
1083 - write_chart_dimension("bandwidth", ((values[2])*8)/1000);
1050 + write_chart_dimension("bandwidth", (collected_number) ((values->bytes_sent)*8)/1000);
1051 ebpf_write_end_chart();
1052
1053 ebpf_write_begin_chart(NETDATA_APP_FAMILY, w->clean_name, "_ebpf_sock_bytes_received");
1054 // We multiply by 0.008, because we read bytes, but we display bits
1088 - write_chart_dimension("bandwidth", ((values[3])*8)/1000);
1055 + write_chart_dimension("bandwidth", (collected_number) ((values->bytes_received)*8)/1000);
1056 ebpf_write_end_chart();
1057
1058 ebpf_write_begin_chart(NETDATA_APP_FAMILY, w->clean_name, "_ebpf_call_tcp_sendmsg");
1092 - write_chart_dimension("calls", values[4]);
1059 + write_chart_dimension("calls", (collected_number) values->call_tcp_sent);
1060 ebpf_write_end_chart();
1061
1062 ebpf_write_begin_chart(NETDATA_APP_FAMILY, w->clean_name, "_ebpf_call_tcp_cleanup_rbuf");
1096 - write_chart_dimension("calls", values[5]);
1063 + write_chart_dimension("calls", (collected_number) values->call_tcp_received);
1064 ebpf_write_end_chart();
1065
1066 ebpf_write_begin_chart(NETDATA_APP_FAMILY, w->clean_name, "_ebpf_call_tcp_retransmit");
1100 - write_chart_dimension("calls", values[6]);
1067 + write_chart_dimension("calls", (collected_number) values->retransmit);
1068 ebpf_write_end_chart();
1069
1070 ebpf_write_begin_chart(NETDATA_APP_FAMILY, w->clean_name, "_ebpf_call_udp_sendmsg");
1104 - write_chart_dimension("calls", values[7]);
1071 + write_chart_dimension("calls", (collected_number) values->call_udp_sent);
1072 ebpf_write_end_chart();
1073
1074 ebpf_write_begin_chart(NETDATA_APP_FAMILY, w->clean_name, "_ebpf_call_udp_recvmsg");
1108 - write_chart_dimension("calls", values[8]);
1075 + write_chart_dimension("calls", (collected_number) values->call_udp_received);
1076 ebpf_write_end_chart();
1077 }
1078 + pthread_mutex_unlock(&collect_data_mutex);
1079 }
1080
1081 /*****************************************************************
@@ -1809,6 +1777,41 @@ end_socket_loop:
1777 }
1778 netdata_thread_enable_cancelability();
1779 }
1780 +/**
1781 + * Resume apps data
1782 + */
1783 +void ebpf_socket_resume_apps_data()
1784 +{
1785 + struct ebpf_target *w;
1786 +
1787 + for (w = apps_groups_root_target; w; w = w->next) {
1788 + if (unlikely(!(w->charts_created & (1<<EBPF_MODULE_SOCKET_IDX))))
1789 + continue;
1790 +
1791 + struct ebpf_pid_on_target *move = w->root_pid;
1792 +
1793 + ebpf_socket_publish_apps_t *values = &w->socket;
1794 + memset(&w->socket, 0, sizeof(ebpf_socket_publish_apps_t));
1795 + while (move) {
1796 + int32_t pid = move->pid;
1797 + ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(pid, 0);
1798 + if (local_pid) {
1799 + ebpf_socket_publish_apps_t *ws = &local_pid->socket;
1800 + values->call_tcp_v4_connection = ws->call_tcp_v4_connection;
1801 + values->call_tcp_v6_connection = ws->call_tcp_v6_connection;
1802 + values->bytes_sent = ws->bytes_sent;
1803 + values->bytes_received = ws->bytes_received;
1804 + values->call_tcp_sent = ws->call_tcp_sent;
1805 + values->call_tcp_received = ws->call_tcp_received;
1806 + values->retransmit = ws->retransmit;
1807 + values->call_udp_sent = ws->call_udp_sent;
1808 + values->call_udp_received = ws->call_udp_received;
1809 + }
1810 +
1811 + move = move->next;
1812 + }
1813 + }
1814 +}
1815
1816 /**
1817 * Socket thread
@@ -1839,7 +1842,10 @@ void *ebpf_read_socket_thread(void *ptr)
1842 if (ebpf_plugin_exit || ++counter != update_every)
1843 continue;
1844
1845 + pthread_mutex_lock(&collect_data_mutex);
1846 ebpf_update_array_vectors(em);
1847 + ebpf_socket_resume_apps_data();
1848 + pthread_mutex_unlock(&collect_data_mutex);
1849
1850 counter = 0;
1851 }
@@ -1992,23 +1998,23 @@ static void ebpf_socket_read_hash_global_tables(netdata_idx_t *stats, int maps_p
1998 */
1999 void ebpf_socket_fill_publish_apps(uint32_t current_pid, netdata_socket_t *ns)
2000 {
1995 - ebpf_socket_publish_apps_t *curr = socket_bandwidth_curr[current_pid];
1996 - if (!curr) {
1997 - curr = ebpf_socket_stat_get();
1998 - socket_bandwidth_curr[current_pid] = curr;
1999 - }
2000 -
2001 - curr->bytes_sent += ns->tcp.tcp_bytes_sent;
2002 - curr->bytes_received += ns->tcp.tcp_bytes_received;
2003 - curr->call_tcp_sent += ns->tcp.call_tcp_sent;
2004 - curr->call_tcp_received += ns->tcp.call_tcp_received;
2005 - curr->retransmit += ns->tcp.retransmit;
2006 - curr->call_close += ns->tcp.close;
2007 - curr->call_tcp_v4_connection += ns->tcp.ipv4_connect;
2008 - curr->call_tcp_v6_connection += ns->tcp.ipv6_connect;
2009 -
2010 - curr->call_udp_sent += ns->udp.call_udp_sent;
2011 - curr->call_udp_received += ns->udp.call_udp_received;
2001 + ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(current_pid, 0);
2002 + if (!local_pid)
2003 + return;
2004 +
2005 + ebpf_socket_publish_apps_t *curr = &local_pid->socket;
2006 +
2007 + curr->bytes_sent = ns->tcp.tcp_bytes_sent;
2008 + curr->bytes_received = ns->tcp.tcp_bytes_received;
2009 + curr->call_tcp_sent = ns->tcp.call_tcp_sent;
2010 + curr->call_tcp_received = ns->tcp.call_tcp_received;
2011 + curr->retransmit = ns->tcp.retransmit;
2012 + curr->call_close = ns->tcp.close;
2013 + curr->call_tcp_v4_connection = ns->tcp.ipv4_connect;
2014 + curr->call_tcp_v6_connection = ns->tcp.ipv6_connect;
2015 +
2016 + curr->call_udp_sent = ns->udp.call_udp_sent;
2017 + curr->call_udp_received = ns->udp.call_udp_received;
2018 }
2019
2020 /**
@@ -2026,8 +2032,9 @@ static void ebpf_update_socket_cgroup()
2032 for (pids = ect->pids; pids; pids = pids->next) {
2033 int pid = pids->pid;
2034 ebpf_socket_publish_apps_t *publish = &ect->publish_socket;
2029 - if (likely(socket_bandwidth_curr) && socket_bandwidth_curr[pid]) {
2030 - ebpf_socket_publish_apps_t *in = socket_bandwidth_curr[pid];
2035 + ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(pid, 0);
2036 + if (local_pid) {
2037 + ebpf_socket_publish_apps_t *in = &local_pid->socket;
2038
2039 publish->bytes_sent = in->bytes_sent;
2040 publish->bytes_received = in->bytes_received;
@@ -2602,7 +2609,6 @@ static void socket_collector(ebpf_module_t *em)
2609 ebpf_socket_read_hash_global_tables(stats, maps_per_core);
2610 }
2611
2605 - pthread_mutex_lock(&collect_data_mutex);
2612 if (cgroups)
2613 ebpf_update_socket_cgroup();
2614
@@ -2611,12 +2617,7 @@ static void socket_collector(ebpf_module_t *em)
2617 ebpf_socket_send_data(em);
2618
2619 if (socket_apps_enabled & NETDATA_EBPF_APPS_FLAG_CHART_CREATED)
2614 - ebpf_socket_send_apps_data(em, apps_groups_root_target);
2615 -
2616 -#ifdef NETDATA_DEV_MODE
2617 - if (ebpf_aral_socket_pid)
2618 - ebpf_send_data_aral_chart(ebpf_aral_socket_pid, em);
2619 -#endif
2620 + ebpf_socket_send_apps_data();
2621
2622 if (cgroups)
2623 ebpf_socket_send_cgroup_data(update_every);
@@ -2624,7 +2625,6 @@ static void socket_collector(ebpf_module_t *em)
2625 fflush(stdout);
2626
2627 pthread_mutex_unlock(&lock);
2627 - pthread_mutex_unlock(&collect_data_mutex);
2628
2629 pthread_mutex_lock(&ebpf_exit_cleanup);
2630 if (running_time && !em->running_time)
@@ -2655,9 +2655,6 @@ static void ebpf_socket_initialize_global_vectors()
2655 memset(socket_publish_aggregated, 0 ,NETDATA_MAX_SOCKET_VECTOR * sizeof(netdata_publish_syscall_t));
2656 socket_hash_values = callocz(ebpf_nprocs, sizeof(netdata_idx_t));
2657
2658 - ebpf_socket_aral_init();
2659 - socket_bandwidth_curr = callocz((size_t)pid_max, sizeof(ebpf_socket_publish_apps_t *));
2660 -
2658 aral_socket_table = ebpf_allocate_pid_aral(NETDATA_EBPF_SOCKET_ARAL_TABLE_NAME,
2659 sizeof(netdata_socket_plus_t));
2660
@@ -2878,11 +2875,6 @@ void *ebpf_socket_thread(void *ptr)
2875 ebpf_update_stats(&plugin_statistics, em);
2876 ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_ADD);
2877
2881 -#ifdef NETDATA_DEV_MODE
2882 - if (ebpf_aral_socket_pid)
2883 - socket_disable_priority = ebpf_statistic_create_aral_chart(NETDATA_EBPF_SOCKET_ARAL_NAME, em);
2884 -#endif
2885 -
2878 pthread_mutex_unlock(&lock);
2879
2880 socket_collector(em);
src/collectors/ebpf.plugin/ebpf_swap.c
+146 -90
@@ -52,6 +52,17 @@ netdata_ebpf_targets_t swap_targets[] = { {.name = "swap_readpage", .mode = EBPF
52 {.name = "swap_writepage", .mode = EBPF_LOAD_TRAMPOLINE},
53 {.name = NULL, .mode = EBPF_LOAD_TRAMPOLINE}};
54
55 +struct netdata_static_thread ebpf_read_swap = {
56 + .name = "EBPF_READ_SWAP",
57 + .config_section = NULL,
58 + .config_name = NULL,
59 + .env_name = NULL,
60 + .enabled = 1,
61 + .thread = NULL,
62 + .init_routine = NULL,
63 + .start_routine = NULL
64 +};
65 +
66 #ifdef LIBBPF_MAJOR_VERSION
67 /**
68 * Disable probe
@@ -269,6 +280,7 @@ void ebpf_obsolete_swap_apps_charts(struct ebpf_module *em)
280 {
281 struct ebpf_target *w;
282 int update_every = em->update_every;
283 + pthread_mutex_lock(&collect_data_mutex);
284 for (w = apps_groups_root_target; w; w = w->next) {
285 if (unlikely(!(w->charts_created & (1<<EBPF_MODULE_SWAP_IDX))))
286 continue;
@@ -296,6 +308,7 @@ void ebpf_obsolete_swap_apps_charts(struct ebpf_module *em)
308 update_every);
309 w->charts_created &= ~(1<<EBPF_MODULE_SWAP_IDX);
310 }
311 + pthread_mutex_unlock(&collect_data_mutex);
312 }
313
314 /**
@@ -329,6 +342,9 @@ static void ebpf_swap_exit(void *ptr)
342 {
343 ebpf_module_t *em = (ebpf_module_t *)ptr;
344
345 + if (ebpf_read_swap.thread)
346 + netdata_thread_cancel(*ebpf_read_swap.thread);
347 +
348 if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
349 pthread_mutex_lock(&lock);
350 if (em->cgroup_charts) {
@@ -391,66 +407,74 @@ static void swap_apps_accumulator(netdata_publish_swap_t *out, int maps_per_core
407 }
408 }
409
394 -/**
395 - * Fill PID
396 - *
397 - * Fill PID structures
398 - *
399 - * @param current_pid pid that we are collecting data
400 - * @param out values read from hash tables;
401 - */
402 -static void swap_fill_pid(uint32_t current_pid, netdata_publish_swap_t *publish)
403 -{
404 - netdata_publish_swap_t *curr = swap_pid[current_pid];
405 - if (!curr) {
406 - curr = callocz(1, sizeof(netdata_publish_swap_t));
407 - swap_pid[current_pid] = curr;
408 - }
409 -
410 - memcpy(curr, publish, sizeof(netdata_publish_swap_t));
411 -}
412 -
410 /**
411 * Update cgroup
412 *
413 * Update cgroup data based in
417 - *
418 - * @param maps_per_core do I need to read all cores?
414 */
420 -static void ebpf_update_swap_cgroup(int maps_per_core)
415 +static void ebpf_update_swap_cgroup()
416 {
417 ebpf_cgroup_target_t *ect ;
423 - netdata_publish_swap_t *cv = swap_vector;
424 - int fd = swap_maps[NETDATA_PID_SWAP_TABLE].map_fd;
425 - size_t length = sizeof(netdata_publish_swap_t);
426 - if (maps_per_core)
427 - length *= ebpf_nprocs;
418 pthread_mutex_lock(&mutex_cgroup_shm);
419 for (ect = ebpf_cgroup_pids; ect; ect = ect->next) {
420 struct pid_on_target2 *pids;
421 for (pids = ect->pids; pids; pids = pids->next) {
422 int pid = pids->pid;
423 netdata_publish_swap_t *out = &pids->swap;
434 - if (likely(swap_pid) && swap_pid[pid]) {
435 - netdata_publish_swap_t *in = swap_pid[pid];
424 + ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(pid, 0);
425 + if (local_pid) {
426 + netdata_publish_swap_t *in = &local_pid->swap;
427
428 memcpy(out, in, sizeof(netdata_publish_swap_t));
438 - } else {
439 - memset(cv, 0, length);
440 - if (!bpf_map_lookup_elem(fd, &pid, cv)) {
441 - swap_apps_accumulator(cv, maps_per_core);
442 -
443 - memcpy(out, cv, sizeof(netdata_publish_swap_t));
444 -
445 - // We are cleaning to avoid passing data read from one process to other.
446 - memset(cv, 0, length);
447 - }
429 }
430 }
431 }
432 pthread_mutex_unlock(&mutex_cgroup_shm);
433 }
434
435 +/**
436 + * Sum PIDs
437 + *
438 + * Sum values for all targets.
439 + *
440 + * @param swap
441 + * @param root
442 + */
443 +static void ebpf_swap_sum_pids(netdata_publish_swap_t *swap, struct ebpf_pid_on_target *root)
444 +{
445 + uint64_t local_read = 0;
446 + uint64_t local_write = 0;
447 +
448 + while (root) {
449 + int32_t pid = root->pid;
450 + ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(pid, 0);
451 + if (local_pid) {
452 + netdata_publish_swap_t *w = &local_pid->swap;
453 + local_write += w->write;
454 + local_read += w->read;
455 + }
456 + root = root->next;
457 + }
458 +
459 + // These conditions were added, because we are using incremental algorithm
460 + swap->write = (local_write >= swap->write) ? local_write : swap->write;
461 + swap->read = (local_read >= swap->read) ? local_read : swap->read;
462 + }
463 +
464 +
465 +/**
466 + * Resume apps data
467 + */
468 +void ebpf_swap_resume_apps_data() {
469 + struct ebpf_target *w;
470 + for (w = apps_groups_root_target; w; w = w->next) {
471 + if (unlikely(!(w->charts_created & (1 << EBPF_MODULE_SWAP_IDX))))
472 + continue;
473 +
474 + ebpf_swap_sum_pids(&w->swap, w->root_pid);
475 + }
476 +}
477 +
478 /**
479 * Read APPS table
480 *
@@ -458,32 +482,94 @@ static void ebpf_update_swap_cgroup(int maps_per_core)
482 *
483 * @param maps_per_core do I need to read all cores?
484 */
461 -static void read_swap_apps_table(int maps_per_core)
485 +static void ebpf_read_swap_apps_table(int maps_per_core, int max_period)
486 {
487 netdata_publish_swap_t *cv = swap_vector;
464 - uint32_t key;
465 - struct ebpf_pid_stat *pids = ebpf_root_of_pids;
488 int fd = swap_maps[NETDATA_PID_SWAP_TABLE].map_fd;
489 size_t length = sizeof(netdata_publish_swap_t);
490 if (maps_per_core)
491 length *= ebpf_nprocs;
470 - while (pids) {
471 - key = pids->pid;
492
493 + uint32_t key = 0, next_key = 0;
494 + while (bpf_map_get_next_key(fd, &key, &next_key) == 0) {
495 if (bpf_map_lookup_elem(fd, &key, cv)) {
474 - pids = pids->next;
475 - continue;
496 + goto end_swap_loop;
497 }
498
499 swap_apps_accumulator(cv, maps_per_core);
500
480 - swap_fill_pid(key, cv);
501 + ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(key, cv->tgid);
502 + if (!local_pid)
503 + goto end_swap_loop;
504 +
505 + netdata_publish_swap_t *publish = &local_pid->swap;
506 + if (!publish->ct || publish->ct != cv->ct) {
507 + memcpy(publish, cv, sizeof(netdata_publish_swap_t));
508 + local_pid->not_updated = 0;
509 + } else if (++local_pid->not_updated >= max_period) {
510 + bpf_map_delete_elem(fd, &key);
511 + local_pid->not_updated = 0;
512 + }
513
514 // We are cleaning to avoid passing data read from one process to other.
515 +end_swap_loop:
516 memset(cv, 0, length);
517 + key = next_key;
518 + }
519 +}
520
485 - pids = pids->next;
521 +/**
522 + * SWAP thread
523 + *
524 + * Thread used to generate swap charts.
525 + *
526 + * @param ptr a pointer to `struct ebpf_module`
527 + *
528 + * @return It always return NULL
529 + */
530 +void *ebpf_read_swap_thread(void *ptr)
531 +{
532 + heartbeat_t hb;
533 + heartbeat_init(&hb);
534 +
535 + ebpf_module_t *em = (ebpf_module_t *)ptr;
536 +
537 + int maps_per_core = em->maps_per_core;
538 + int update_every = em->update_every;
539 +
540 + int counter = update_every - 1;
541 +
542 + uint32_t lifetime = em->lifetime;
543 + uint32_t running_time = 0;
544 + usec_t period = update_every * USEC_PER_SEC;
545 + int max_period = update_every * EBPF_CLEANUP_FACTOR;
546 +
547 + while (!ebpf_plugin_exit && running_time < lifetime) {
548 + (void)heartbeat_next(&hb, period);
549 + if (ebpf_plugin_exit || ++counter != update_every)
550 + continue;
551 +
552 + netdata_thread_disable_cancelability();
553 +
554 + pthread_mutex_lock(&collect_data_mutex);
555 + ebpf_read_swap_apps_table(maps_per_core, max_period);
556 + ebpf_swap_resume_apps_data();
557 + pthread_mutex_unlock(&collect_data_mutex);
558 +
559 + counter = 0;
560 +
561 + pthread_mutex_lock(&ebpf_exit_cleanup);
562 + if (running_time && !em->running_time)
563 + running_time = update_every;
564 + else
565 + running_time += update_every;
566 +
567 + em->running_time = running_time;
568 + pthread_mutex_unlock(&ebpf_exit_cleanup);
569 + netdata_thread_enable_cancelability();
570 }
571 +
572 + return NULL;
573 }
574
575 /**
@@ -525,34 +611,6 @@ static void ebpf_swap_read_global_table(netdata_idx_t *stats, int maps_per_core)
611 NETDATA_CONTROLLER_END);
612 }
613
528 -/**
529 - * Sum PIDs
530 - *
531 - * Sum values for all targets.
532 - *
533 - * @param swap
534 - * @param root
535 - */
536 -static void ebpf_swap_sum_pids(netdata_publish_swap_t *swap, struct ebpf_pid_on_target *root)
537 -{
538 - uint64_t local_read = 0;
539 - uint64_t local_write = 0;
540 -
541 - while (root) {
542 - int32_t pid = root->pid;
543 - netdata_publish_swap_t *w = swap_pid[pid];
544 - if (w) {
545 - local_write += w->write;
546 - local_read += w->read;
547 - }
548 - root = root->next;
549 - }
550 -
551 - // These conditions were added, because we are using incremental algorithm
552 - swap->write = (local_write >= swap->write) ? local_write : swap->write;
553 - swap->read = (local_read >= swap->read) ? local_read : swap->read;
554 -}
555 -
614 /**
615 * Send data to Netdata calling auxiliary functions.
616 *
@@ -561,12 +619,11 @@ static void ebpf_swap_sum_pids(netdata_publish_swap_t *swap, struct ebpf_pid_on_
619 void ebpf_swap_send_apps_data(struct ebpf_target *root)
620 {
621 struct ebpf_target *w;
622 + pthread_mutex_lock(&collect_data_mutex);
623 for (w = root; w; w = w->next) {
624 if (unlikely(!(w->charts_created & (1<<EBPF_MODULE_SWAP_IDX))))
625 continue;
626
568 - ebpf_swap_sum_pids(&w->swap, w->root_pid);
569 -
627 ebpf_write_begin_chart(NETDATA_APP_FAMILY, w->clean_name, "_ebpf_call_swap_readpage");
628 write_chart_dimension("calls", (long long) w->swap.read);
629 ebpf_write_end_chart();
@@ -575,6 +632,7 @@ void ebpf_swap_send_apps_data(struct ebpf_target *root)
632 write_chart_dimension("calls", (long long) w->swap.write);
633 ebpf_write_end_chart();
634 }
635 + pthread_mutex_unlock(&collect_data_mutex);
636 }
637
638 /**
@@ -791,12 +849,9 @@ static void swap_collector(ebpf_module_t *em)
849 counter = 0;
850 netdata_apps_integration_flags_t apps = em->apps_charts;
851 ebpf_swap_read_global_table(stats, maps_per_core);
794 - pthread_mutex_lock(&collect_data_mutex);
795 - if (apps)
796 - read_swap_apps_table(maps_per_core);
852
853 if (cgroup)
799 - ebpf_update_swap_cgroup(maps_per_core);
854 + ebpf_update_swap_cgroup();
855
856 pthread_mutex_lock(&lock);
857
@@ -809,7 +864,6 @@ static void swap_collector(ebpf_module_t *em)
864 ebpf_swap_send_cgroup_data(update_every);
865
866 pthread_mutex_unlock(&lock);
812 - pthread_mutex_unlock(&collect_data_mutex);
867
868 pthread_mutex_lock(&ebpf_exit_cleanup);
869 if (running_time && !em->running_time)
@@ -884,14 +938,9 @@ void ebpf_swap_create_apps_charts(struct ebpf_module *em, void *ptr)
938 *
939 * We are not testing the return, because callocz does this and shutdown the software
940 * case it was not possible to allocate.
887 - *
888 - * @param apps is apps enabled?
941 */
890 -static void ebpf_swap_allocate_global_vectors(int apps)
942 +static void ebpf_swap_allocate_global_vectors()
943 {
892 - if (apps)
893 - swap_pid = callocz((size_t)pid_max, sizeof(netdata_publish_swap_t *));
894 -
944 swap_vector = callocz((size_t)ebpf_nprocs, sizeof(netdata_publish_swap_t));
945
946 swap_values = callocz((size_t)ebpf_nprocs, sizeof(netdata_idx_t));
@@ -989,7 +1038,7 @@ void *ebpf_swap_thread(void *ptr)
1038 goto endswap;
1039 }
1040
992 - ebpf_swap_allocate_global_vectors(em->apps_charts);
1041 + ebpf_swap_allocate_global_vectors();
1042
1043 int algorithms[NETDATA_SWAP_END] = { NETDATA_EBPF_INCREMENTAL_IDX, NETDATA_EBPF_INCREMENTAL_IDX };
1044 ebpf_global_labels(swap_aggregated_data, swap_publish_aggregated, swap_dimension_name, swap_dimension_name,
@@ -1001,6 +1050,13 @@ void *ebpf_swap_thread(void *ptr)
1050 ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_ADD);
1051 pthread_mutex_unlock(&lock);
1052
1053 + ebpf_read_swap.thread = mallocz(sizeof(netdata_thread_t));
1054 + netdata_thread_create(ebpf_read_swap.thread,
1055 + ebpf_read_swap.name,
1056 + NETDATA_THREAD_OPTION_DEFAULT,
1057 + ebpf_read_swap_thread,
1058 + em);
1059 +
1060 swap_collector(em);
1061
1062 endswap:
src/collectors/ebpf.plugin/ebpf_vfs.c
+121 -82
@@ -1,7 +1,5 @@
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 -#include <sys/resource.h>
4 -
3 #include "ebpf.h"
4 #include "ebpf_vfs.h"
5
@@ -43,6 +41,17 @@ static ebpf_local_maps_t vfs_maps[] = {{.name = "tbl_vfs_pid", .internal_input =
41 #endif
42 }};
43
44 +struct netdata_static_thread ebpf_read_vfs = {
45 + .name = "EBPF_READ_VFS",
46 + .config_section = NULL,
47 + .config_name = NULL,
48 + .env_name = NULL,
49 + .enabled = 1,
50 + .thread = NULL,
51 + .init_routine = NULL,
52 + .start_routine = NULL
53 +};
54 +
55 struct config vfs_config = { .first_section = NULL,
56 .last_section = NULL,
57 .mutex = NETDATA_MUTEX_INITIALIZER,
@@ -60,10 +69,6 @@ netdata_ebpf_targets_t vfs_targets[] = { {.name = "vfs_write", .mode = EBPF_LOAD
69 {.name = "release_task", .mode = EBPF_LOAD_TRAMPOLINE},
70 {.name = NULL, .mode = EBPF_LOAD_TRAMPOLINE}};
71
63 -#ifdef NETDATA_DEV_MODE
64 -int vfs_disable_priority;
65 -#endif
66 -
72 #ifdef LIBBPF_MAJOR_VERSION
73 /**
74 * Disable probe
@@ -168,7 +173,7 @@ static int ebpf_vfs_attach_probe(struct vfs_bpf *obj)
173 {
174 obj->links.netdata_vfs_write_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_vfs_write_kprobe, false,
175 vfs_targets[NETDATA_EBPF_VFS_WRITE].name);
171 - int ret = libbpf_get_error(obj->links.netdata_vfs_write_kprobe);
176 + long ret = libbpf_get_error(obj->links.netdata_vfs_write_kprobe);
177 if (ret)
178 return -1;
179
@@ -578,6 +583,7 @@ void ebpf_obsolete_vfs_apps_charts(struct ebpf_module *em)
583 int order = 20275;
584 struct ebpf_target *w;
585 int update_every = em->update_every;
586 + pthread_mutex_lock(&collect_data_mutex);
587 for (w = apps_groups_root_target; w; w = w->next) {
588 if (unlikely(!(w->charts_created & (1<<EBPF_MODULE_VFS_IDX))))
589 continue;
@@ -736,6 +742,7 @@ void ebpf_obsolete_vfs_apps_charts(struct ebpf_module *em)
742 }
743 w->charts_created &= ~(1<<EBPF_MODULE_VFS_IDX);
744 }
745 + pthread_mutex_unlock(&collect_data_mutex);
746 }
747
748 /**
@@ -877,6 +884,9 @@ static void ebpf_vfs_exit(void *ptr)
884 {
885 ebpf_module_t *em = (ebpf_module_t *)ptr;
886
887 + if (ebpf_read_vfs.thread)
888 + netdata_thread_cancel(*ebpf_read_vfs.thread);
889 +
890 if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
891 pthread_mutex_lock(&lock);
892 if (em->cgroup_charts) {
@@ -890,11 +900,6 @@ static void ebpf_vfs_exit(void *ptr)
900
901 ebpf_obsolete_vfs_global(em);
902
893 -#ifdef NETDATA_DEV_MODE
894 - if (ebpf_aral_vfs_pid)
895 - ebpf_statistic_obsolete_aral_chart(em, vfs_disable_priority);
896 -#endif
897 -
903 fflush(stdout);
904 pthread_mutex_unlock(&lock);
905 }
@@ -1041,8 +1046,9 @@ static void ebpf_vfs_sum_pids(netdata_publish_vfs_t *vfs, struct ebpf_pid_on_tar
1046
1047 while (root) {
1048 int32_t pid = root->pid;
1044 - netdata_publish_vfs_t *w = vfs_pid[pid];
1045 - if (w) {
1049 + ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(pid, 0);
1050 + if (local_pid) {
1051 + netdata_publish_vfs_t *w = &local_pid->vfs;
1052 accumulator.write_call += w->write_call;
1053 accumulator.writev_call += w->writev_call;
1054 accumulator.read_call += w->read_call;
@@ -1103,12 +1109,11 @@ static void ebpf_vfs_sum_pids(netdata_publish_vfs_t *vfs, struct ebpf_pid_on_tar
1109 void ebpf_vfs_send_apps_data(ebpf_module_t *em, struct ebpf_target *root)
1110 {
1111 struct ebpf_target *w;
1112 + pthread_mutex_lock(&collect_data_mutex);
1113 for (w = root; w; w = w->next) {
1114 if (unlikely(!(w->charts_created & (1<<EBPF_MODULE_VFS_IDX))))
1115 continue;
1116
1110 - ebpf_vfs_sum_pids(&w->vfs, w->root_pid);
1111 -
1117 ebpf_write_begin_chart(NETDATA_APP_FAMILY, w->clean_name, "_ebpf_call_vfs_unlink");
1118 write_chart_dimension("calls", w->vfs.unlink_call);
1119 ebpf_write_end_chart();
@@ -1171,6 +1176,7 @@ void ebpf_vfs_send_apps_data(ebpf_module_t *em, struct ebpf_target *root)
1176 ebpf_write_end_chart();
1177 }
1178 }
1179 + pthread_mutex_unlock(&collect_data_mutex);
1180 }
1181
1182 /**
@@ -1206,53 +1212,42 @@ static void vfs_apps_accumulator(netdata_publish_vfs_t *out, int maps_per_core)
1212 }
1213 }
1214
1209 -/**
1210 - * Fill PID
1211 - *
1212 - * Fill PID structures
1213 - *
1214 - * @param current_pid pid that we are collecting data
1215 - * @param out values read from hash tables;
1216 - */
1217 -static void vfs_fill_pid(uint32_t current_pid, netdata_publish_vfs_t *publish)
1218 -{
1219 - netdata_publish_vfs_t *curr = vfs_pid[current_pid];
1220 - if (!curr) {
1221 - curr = ebpf_vfs_get();
1222 - vfs_pid[current_pid] = curr;
1223 - }
1224 -
1225 - memcpy(curr, &publish[0], sizeof(netdata_publish_vfs_t));
1226 -}
1227 -
1215 /**
1216 * Read the hash table and store data to allocated vectors.
1217 */
1231 -static void ebpf_vfs_read_apps(int maps_per_core)
1218 +static void ebpf_vfs_read_apps(int maps_per_core, int max_period)
1219 {
1233 - struct ebpf_pid_stat *pids = ebpf_root_of_pids;
1220 netdata_publish_vfs_t *vv = vfs_vector;
1221 int fd = vfs_maps[NETDATA_VFS_PID].map_fd;
1222 size_t length = sizeof(netdata_publish_vfs_t);
1223 if (maps_per_core)
1224 length *= ebpf_nprocs;
1225
1240 - while (pids) {
1241 - uint32_t key = pids->pid;
1242 -
1226 + uint32_t key = 0, next_key = 0;
1227 + while (bpf_map_get_next_key(fd, &key, &next_key) == 0) {
1228 if (bpf_map_lookup_elem(fd, &key, vv)) {
1244 - pids = pids->next;
1245 - continue;
1229 + goto end_vfs_loop;
1230 }
1231
1232 vfs_apps_accumulator(vv, maps_per_core);
1233
1250 - vfs_fill_pid(key, vv);
1234 + ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(key, vv->tgid);
1235 + if (!local_pid)
1236 + goto end_vfs_loop;
1237 +
1238 + netdata_publish_vfs_t *publish = &local_pid->vfs;
1239 + if (!publish->ct || publish->ct != vv->ct) {
1240 + memcpy(publish, vv, sizeof(netdata_publish_vfs_t));
1241 + local_pid->not_updated = 0;
1242 + } else if (++local_pid->not_updated >= max_period){
1243 + bpf_map_delete_elem(fd, &key);
1244 + local_pid->not_updated = 0;
1245 + }
1246
1247 +end_vfs_loop:
1248 // We are cleaning to avoid passing data read from one process to other.
1249 memset(vv, 0, length);
1254 -
1255 - pids = pids->next;
1250 + key = next_key;
1251 }
1252 }
1253
@@ -1263,32 +1258,20 @@ static void ebpf_vfs_read_apps(int maps_per_core)
1258 *
1259 * @param maps_per_core do I need to read all cores?
1260 */
1266 -static void read_update_vfs_cgroup(int maps_per_core)
1261 +static void read_update_vfs_cgroup()
1262 {
1263 ebpf_cgroup_target_t *ect ;
1269 - netdata_publish_vfs_t *vv = vfs_vector;
1270 - int fd = vfs_maps[NETDATA_VFS_PID].map_fd;
1271 - size_t length = sizeof(netdata_publish_vfs_t);
1272 - if (maps_per_core)
1273 - length *= ebpf_nprocs;
1274 -
1264 pthread_mutex_lock(&mutex_cgroup_shm);
1265 for (ect = ebpf_cgroup_pids; ect; ect = ect->next) {
1266 struct pid_on_target2 *pids;
1267 for (pids = ect->pids; pids; pids = pids->next) {
1268 int pid = pids->pid;
1269 netdata_publish_vfs_t *out = &pids->vfs;
1281 - if (likely(vfs_pid) && vfs_pid[pid]) {
1282 - netdata_publish_vfs_t *in = vfs_pid[pid];
1270 + ebpf_pid_stat_t *local_pid = ebpf_get_pid_entry(pid, 0);
1271 + if (local_pid) {
1272 + netdata_publish_vfs_t *in = &local_pid->vfs;
1273
1274 memcpy(out, in, sizeof(netdata_publish_vfs_t));
1285 - } else {
1286 - memset(vv, 0, length);
1287 - if (!bpf_map_lookup_elem(fd, &pid, vv)) {
1288 - vfs_apps_accumulator(vv, maps_per_core);
1289 -
1290 - memcpy(out, vv, sizeof(netdata_publish_vfs_t));
1291 - }
1275 }
1276 }
1277 }
@@ -1908,6 +1891,72 @@ static void ebpf_vfs_send_cgroup_data(ebpf_module_t *em)
1891 pthread_mutex_unlock(&mutex_cgroup_shm);
1892 }
1893
1894 +/**
1895 + * Resume apps data
1896 + */
1897 +void ebpf_vfs_resume_apps_data() {
1898 + struct ebpf_target *w;
1899 + for (w = apps_groups_root_target; w; w = w->next) {
1900 + if (unlikely(!(w->charts_created & (1 << EBPF_MODULE_VFS_IDX))))
1901 + continue;
1902 +
1903 + ebpf_vfs_sum_pids(&w->vfs, w->root_pid);
1904 + }
1905 +}
1906 +
1907 +/**
1908 + * VFS thread
1909 + *
1910 + * Thread used to generate charts.
1911 + *
1912 + * @param ptr a pointer to `struct ebpf_module`
1913 + *
1914 + * @return It always return NULL
1915 + */
1916 +void *ebpf_read_vfs_thread(void *ptr)
1917 +{
1918 + heartbeat_t hb;
1919 + heartbeat_init(&hb);
1920 +
1921 + ebpf_module_t *em = (ebpf_module_t *)ptr;
1922 +
1923 + int maps_per_core = em->maps_per_core;
1924 + int update_every = em->update_every;
1925 +
1926 + int counter = update_every - 1;
1927 +
1928 + uint32_t lifetime = em->lifetime;
1929 + uint32_t running_time = 0;
1930 + usec_t period = update_every * USEC_PER_SEC;
1931 + int max_period = update_every * EBPF_CLEANUP_FACTOR;
1932 + while (!ebpf_plugin_exit && running_time < lifetime) {
1933 + (void)heartbeat_next(&hb, period);
1934 + if (ebpf_plugin_exit || ++counter != update_every)
1935 + continue;
1936 +
1937 + netdata_thread_disable_cancelability();
1938 +
1939 + pthread_mutex_lock(&collect_data_mutex);
1940 + ebpf_vfs_read_apps(maps_per_core, max_period);
1941 + ebpf_vfs_resume_apps_data();
1942 + pthread_mutex_unlock(&collect_data_mutex);
1943 +
1944 + counter = 0;
1945 +
1946 + pthread_mutex_lock(&ebpf_exit_cleanup);
1947 + if (running_time && !em->running_time)
1948 + running_time = update_every;
1949 + else
1950 + running_time += update_every;
1951 +
1952 + em->running_time = running_time;
1953 + pthread_mutex_unlock(&ebpf_exit_cleanup);
1954 + netdata_thread_enable_cancelability();
1955 + }
1956 +
1957 + return NULL;
1958 +}
1959 +
1960 /**
1961 * Main loop for this collector.
1962 *
@@ -1934,20 +1983,12 @@ static void vfs_collector(ebpf_module_t *em)
1983 counter = 0;
1984 netdata_apps_integration_flags_t apps = em->apps_charts;
1985 ebpf_vfs_read_global_table(stats, maps_per_core);
1937 - pthread_mutex_lock(&collect_data_mutex);
1938 - if (apps)
1939 - ebpf_vfs_read_apps(maps_per_core);
1986
1987 if (cgroups)
1942 - read_update_vfs_cgroup(maps_per_core);
1988 + read_update_vfs_cgroup();
1989
1990 pthread_mutex_lock(&lock);
1991
1946 -#ifdef NETDATA_DEV_MODE
1947 - if (ebpf_aral_vfs_pid)
1948 - ebpf_send_data_aral_chart(ebpf_aral_vfs_pid, em);
1949 -#endif
1950 -
1992 ebpf_vfs_send_data(em);
1993 fflush(stdout);
1994
@@ -1958,7 +1999,6 @@ static void vfs_collector(ebpf_module_t *em)
1999 ebpf_vfs_send_cgroup_data(em);
2000
2001 pthread_mutex_unlock(&lock);
1961 - pthread_mutex_unlock(&collect_data_mutex);
2002
2003 pthread_mutex_lock(&ebpf_exit_cleanup);
2004 if (running_time && !em->running_time)
@@ -2385,13 +2425,9 @@ void ebpf_vfs_create_apps_charts(struct ebpf_module *em, void *ptr)
2425 *
2426 * @param apps is apps enabled?
2427 */
2388 -static void ebpf_vfs_allocate_global_vectors(int apps)
2428 +static void ebpf_vfs_allocate_global_vectors()
2429 {
2390 - if (apps) {
2391 - ebpf_vfs_aral_init();
2392 - vfs_pid = callocz((size_t)pid_max, sizeof(netdata_publish_vfs_t *));
2393 - vfs_vector = callocz(ebpf_nprocs, sizeof(netdata_publish_vfs_t));
2394 - }
2430 + vfs_vector = callocz(ebpf_nprocs, sizeof(netdata_publish_vfs_t));
2431
2432 memset(vfs_aggregated_data, 0, sizeof(vfs_aggregated_data));
2433 memset(vfs_publish_aggregated, 0, sizeof(vfs_publish_aggregated));
@@ -2457,7 +2493,7 @@ void *ebpf_vfs_thread(void *ptr)
2493
2494 ebpf_update_pid_table(&vfs_maps[NETDATA_VFS_PID], em);
2495
2460 - ebpf_vfs_allocate_global_vectors(em->apps_charts);
2496 + ebpf_vfs_allocate_global_vectors();
2497
2498 #ifdef LIBBPF_MAJOR_VERSION
2499 ebpf_adjust_thread_load(em, default_btf);
@@ -2478,13 +2514,16 @@ void *ebpf_vfs_thread(void *ptr)
2514 ebpf_create_global_charts(em);
2515 ebpf_update_stats(&plugin_statistics, em);
2516 ebpf_update_kernel_memory_with_vector(&plugin_statistics, em->maps, EBPF_ACTION_STAT_ADD);
2481 -#ifdef NETDATA_DEV_MODE
2482 - if (ebpf_aral_vfs_pid)
2483 - vfs_disable_priority = ebpf_statistic_create_aral_chart(NETDATA_EBPF_VFS_ARAL_NAME, em);
2484 -#endif
2517
2518 pthread_mutex_unlock(&lock);
2519
2520 + ebpf_read_vfs.thread = mallocz(sizeof(netdata_thread_t));
2521 + netdata_thread_create(ebpf_read_vfs.thread,
2522 + ebpf_read_vfs.name,
2523 + NETDATA_THREAD_OPTION_DEFAULT,
2524 + ebpf_read_vfs_thread,
2525 + em);
2526 +
2527 vfs_collector(em);
2528
2529 endvfs: