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: