eBPF Shared Memory system call tracking (#11560)
Uman Shahzad committed
Sep 29, 2021 at 05:53 UTC
5e91a7bc0c8b33a8c45d1c20c90af266ebe96454
16 files changed
+696
-44
CMakeLists.txt
+2
@@ -504,6 +504,8 @@ set(EBPF_PROCESS_PLUGIN_FILES
504
collectors/ebpf.plugin/ebpf_oomkill.h
505
collectors/ebpf.plugin/ebpf_process.c
506
collectors/ebpf.plugin/ebpf_process.h
507
+ collectors/ebpf.plugin/ebpf_shm.c
508
+ collectors/ebpf.plugin/ebpf_shm.h
509
collectors/ebpf.plugin/ebpf_socket.c
510
collectors/ebpf.plugin/ebpf_socket.h
511
collectors/ebpf.plugin/ebpf_softirq.c
Makefile.am
+2
@@ -308,6 +308,8 @@ EBPF_PLUGIN_FILES = \
308
collectors/ebpf.plugin/ebpf_oomkill.h \
309
collectors/ebpf.plugin/ebpf_process.c \
310
collectors/ebpf.plugin/ebpf_process.h \
311
+ collectors/ebpf.plugin/ebpf_shm.c \
312
+ collectors/ebpf.plugin/ebpf_shm.h \
313
collectors/ebpf.plugin/ebpf_socket.c \
314
collectors/ebpf.plugin/ebpf_socket.h \
315
collectors/ebpf.plugin/ebpf_softirq.c \
collectors/all.h
+35
-34
@@ -30,40 +30,41 @@
30
// - for each FAMILY +100
31
// - for each CHART +10
32
33
-#define NETDATA_CHART_PRIO_SYSTEM_CPU 100
34
-#define NETDATA_CHART_PRIO_SYSTEM_LOAD 100
35
-#define NETDATA_CHART_PRIO_SYSTEM_IO 150
36
-#define NETDATA_CHART_PRIO_SYSTEM_PGPGIO 151
37
-#define NETDATA_CHART_PRIO_SYSTEM_RAM 200
38
-#define NETDATA_CHART_PRIO_SYSTEM_SWAP 201
39
-#define NETDATA_CHART_PRIO_SYSTEM_SWAPIO 250
40
-#define NETDATA_CHART_PRIO_SYSTEM_NET 500
41
-#define NETDATA_CHART_PRIO_SYSTEM_IPV4 500 // freebsd only
42
-#define NETDATA_CHART_PRIO_SYSTEM_IP 501
43
-#define NETDATA_CHART_PRIO_SYSTEM_IPV6 502
44
-#define NETDATA_CHART_PRIO_SYSTEM_PROCESSES 600
45
-#define NETDATA_CHART_PRIO_SYSTEM_FORKS 700
46
-#define NETDATA_CHART_PRIO_SYSTEM_ACTIVE_PROCESSES 750
47
-#define NETDATA_CHART_PRIO_SYSTEM_CTXT 800
48
-#define NETDATA_CHART_PRIO_SYSTEM_IDLEJITTER 800
49
-#define NETDATA_CHART_PRIO_SYSTEM_INTR 900
50
-#define NETDATA_CHART_PRIO_SYSTEM_SOFTIRQS 950
51
-#define NETDATA_CHART_PRIO_SYSTEM_SOFTNET_STAT 955
52
-#define NETDATA_CHART_PRIO_SYSTEM_INTERRUPTS 1000
53
-#define NETDATA_CHART_PRIO_SYSTEM_DEV_INTR 1000 // freebsd only
54
-#define NETDATA_CHART_PRIO_SYSTEM_SOFT_INTR 1100 // freebsd only
55
-#define NETDATA_CHART_PRIO_SYSTEM_ENTROPY 1000
56
-#define NETDATA_CHART_PRIO_SYSTEM_UPTIME 1000
57
-#define NETDATA_CHART_PRIO_CLOCK_SYNC_STATE 1100
58
-#define NETDATA_CHART_PRIO_CLOCK_SYNC_OFFSET 1110
59
-#define NETDATA_CHART_PRIO_SYSTEM_IPC_MSQ_QUEUES 1200 // freebsd only
60
-#define NETDATA_CHART_PRIO_SYSTEM_IPC_MSQ_MESSAGES 1201
61
-#define NETDATA_CHART_PRIO_SYSTEM_IPC_MSQ_SIZE 1202
62
-#define NETDATA_CHART_PRIO_SYSTEM_IPC_SEMAPHORES 1203
63
-#define NETDATA_CHART_PRIO_SYSTEM_IPC_SEM_ARRAYS 1204
64
-#define NETDATA_CHART_PRIO_SYSTEM_IPC_SHARED_MEM_SEGS 1205
65
-#define NETDATA_CHART_PRIO_SYSTEM_IPC_SHARED_MEM_SIZE 1206
66
-#define NETDATA_CHART_PRIO_SYSTEM_PACKETS 7001 // freebsd only
33
+#define NETDATA_CHART_PRIO_SYSTEM_CPU 100
34
+#define NETDATA_CHART_PRIO_SYSTEM_LOAD 100
35
+#define NETDATA_CHART_PRIO_SYSTEM_IO 150
36
+#define NETDATA_CHART_PRIO_SYSTEM_PGPGIO 151
37
+#define NETDATA_CHART_PRIO_SYSTEM_RAM 200
38
+#define NETDATA_CHART_PRIO_SYSTEM_SWAP 201
39
+#define NETDATA_CHART_PRIO_SYSTEM_SWAPIO 250
40
+#define NETDATA_CHART_PRIO_SYSTEM_NET 500
41
+#define NETDATA_CHART_PRIO_SYSTEM_IPV4 500 // freebsd only
42
+#define NETDATA_CHART_PRIO_SYSTEM_IP 501
43
+#define NETDATA_CHART_PRIO_SYSTEM_IPV6 502
44
+#define NETDATA_CHART_PRIO_SYSTEM_PROCESSES 600
45
+#define NETDATA_CHART_PRIO_SYSTEM_FORKS 700
46
+#define NETDATA_CHART_PRIO_SYSTEM_ACTIVE_PROCESSES 750
47
+#define NETDATA_CHART_PRIO_SYSTEM_CTXT 800
48
+#define NETDATA_CHART_PRIO_SYSTEM_IDLEJITTER 800
49
+#define NETDATA_CHART_PRIO_SYSTEM_INTR 900
50
+#define NETDATA_CHART_PRIO_SYSTEM_SOFTIRQS 950
51
+#define NETDATA_CHART_PRIO_SYSTEM_SOFTNET_STAT 955
52
+#define NETDATA_CHART_PRIO_SYSTEM_INTERRUPTS 1000
53
+#define NETDATA_CHART_PRIO_SYSTEM_DEV_INTR 1000 // freebsd only
54
+#define NETDATA_CHART_PRIO_SYSTEM_SOFT_INTR 1100 // freebsd only
55
+#define NETDATA_CHART_PRIO_SYSTEM_ENTROPY 1000
56
+#define NETDATA_CHART_PRIO_SYSTEM_UPTIME 1000
57
+#define NETDATA_CHART_PRIO_CLOCK_SYNC_STATE 1100
58
+#define NETDATA_CHART_PRIO_CLOCK_SYNC_OFFSET 1110
59
+#define NETDATA_CHART_PRIO_SYSTEM_IPC_MSQ_QUEUES 1200 // freebsd only
60
+#define NETDATA_CHART_PRIO_SYSTEM_IPC_MSQ_MESSAGES 1201
61
+#define NETDATA_CHART_PRIO_SYSTEM_IPC_MSQ_SIZE 1202
62
+#define NETDATA_CHART_PRIO_SYSTEM_IPC_SEMAPHORES 1203
63
+#define NETDATA_CHART_PRIO_SYSTEM_IPC_SEM_ARRAYS 1204
64
+#define NETDATA_CHART_PRIO_SYSTEM_IPC_SHARED_MEM_SEGS 1205
65
+#define NETDATA_CHART_PRIO_SYSTEM_IPC_SHARED_MEM_SIZE 1206
66
+#define NETDATA_CHART_PRIO_SYSTEM_IPC_SHARED_MEM_CALLS 1207
67
+#define NETDATA_CHART_PRIO_SYSTEM_PACKETS 7001 // freebsd only
68
69
70
// CPU per core
collectors/ebpf.plugin/Makefile.am
+1
@@ -33,6 +33,7 @@ dist_ebpfconfig_DATA = \
33
ebpf.d/network.conf \
34
ebpf.d/oomkill.conf \
35
ebpf.d/process.conf \
36
+ ebpf.d/shm.conf \
37
ebpf.d/softirq.conf \
38
ebpf.d/sync.conf \
39
ebpf.d/swap.conf \
collectors/ebpf.plugin/README.md
+4
-2
@@ -311,8 +311,10 @@ When the integration is enabled, eBPF collector allocates memory for each proces
311
The eBPF collector enables and runs the following eBPF programs by default:
312
313
- `fd` : This eBPF program creates charts that show information about calls to open files.
314
-- `mount`: This eBPF program creates charts that show calls for syscalls mount(2) and umount(2).
315
-- `sync`: Montitor calls for syscalls sync(2), fsync(2), fdatasync(2), syncfs(2), msync(2), and sync_file_range(2).
314
+- `mount`: This eBPF program creates charts that show calls to syscalls mount(2) and umount(2).
315
+- `shm`: This eBPF program creates charts that show calls to syscalls
316
+ shmget(2), shmat(2), shmdt(2) and shmctl(2).
317
+- `sync`: Montitor calls to syscalls sync(2), fsync(2), fdatasync(2), syncfs(2), msync(2), and sync_file_range(2).
318
- `network viewer`: This eBPF program creates charts with information about `TCP` and `UDP` functions, including the
319
bandwidth consumed by each.
320
- `vfs`: This eBPF program creates charts that show information about VFS (Virtual File System) functions.
collectors/ebpf.plugin/ebpf.c
+34
-3
@@ -145,6 +145,11 @@ ebpf_module_t ebpf_modules[] = {
145
.optional = 0, .apps_routine = ebpf_oomkill_create_apps_charts, .maps = NULL,
146
.pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &oomkill_config,
147
.config_file = NETDATA_OOMKILL_CONFIG_FILE},
148
+ { .thread_name = "shm", .config_name = "shm", .enabled = 0, .start_routine = ebpf_shm_thread,
149
+ .update_time = 1, .global_charts = 1, .apps_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY,
150
+ .optional = 0, .apps_routine = ebpf_shm_create_apps_charts, .maps = NULL,
151
+ .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &shm_config,
152
+ .config_file = NETDATA_DIRECTORY_SHM_CONFIG_FILE},
153
{ .thread_name = NULL, .enabled = 0, .start_routine = NULL, .update_time = 1,
154
.global_charts = 0, .apps_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY,
155
.optional = 0, .apps_routine = NULL, .maps = NULL, .pid_map_size = 0, .names = NULL,
@@ -225,6 +230,12 @@ static void ebpf_exit(int sig)
230
freez(fd_pid);
231
}
232
233
+ if (ebpf_modules[EBPF_MODULE_SHM_IDX].enabled) {
234
+ ebpf_modules[EBPF_MODULE_SHM_IDX].enabled = 0;
235
+ clean_shm_pid_structures();
236
+ freez(shm_pid);
237
+ }
238
+
239
/*
240
int ret = fork();
241
if (ret < 0) // error
@@ -740,7 +751,9 @@ void ebpf_print_help()
751
" --process or -p Enable charts related to process run time.\n"
752
"\n"
753
" --return or -r Run the collector in return mode.\n"
743
- "\n",
754
+ "\n"
755
+ " --shm or -b Enable chart related to shared memory tracking.\n"
756
+ "\n"
757
" --softirq or -t Enable chart related to soft IRQ latency.\n"
758
"\n"
759
" --sync or -s Enable chart related to sync run time.\n"
@@ -748,7 +761,7 @@ void ebpf_print_help()
761
" --swap or -w Enable chart related to swap run time.\n"
762
"\n"
763
" --vfs or -f Enable chart related to vfs run time.\n"
751
- "\n"
764
+ "\n",
765
VERSION,
766
(year >= 116) ? year + 1900 : 2020);
767
}
@@ -1168,6 +1181,13 @@ static void read_collector_values(int *disable_apps)
1181
started++;
1182
}
1183
1184
+ enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "shm",
1185
+ CONFIG_BOOLEAN_YES);
1186
+ if (enabled) {
1187
+ ebpf_enable_chart(EBPF_MODULE_SHM_IDX, *disable_apps);
1188
+ started++;
1189
+ }
1190
+
1191
if (!started){
1192
ebpf_enable_all_charts(*disable_apps);
1193
// Read network viewer section
@@ -1263,6 +1283,7 @@ static void parse_args(int argc, char **argv)
1283
{"oomkill", no_argument, 0, 'o' },
1284
{"process", no_argument, 0, 'p' },
1285
{"return", no_argument, 0, 'r' },
1286
+ {"shm", no_argument, 0, 'b' },
1287
{"softirq", no_argument, 0, 't' },
1288
{"sync", no_argument, 0, 's' },
1289
{"swap", no_argument, 0, 'w' },
@@ -1281,7 +1302,7 @@ static void parse_args(int argc, char **argv)
1302
}
1303
1304
while (1) {
1284
- int c = getopt_long(argc, argv, "hvgacdkieqmnoprtswf", long_options, &option_index);
1305
+ int c = getopt_long(argc, argv, "hvgacdkieqmnoprbtswf", long_options, &option_index);
1306
if (c == -1)
1307
break;
1308
@@ -1397,6 +1418,14 @@ static void parse_args(int argc, char **argv)
1418
ebpf_set_thread_mode(MODE_RETURN);
1419
#ifdef NETDATA_INTERNAL_CHECKS
1420
info("EBPF running in \"return\" mode, because it was started with the option \"--return\" or \"-r\".");
1421
+#endif
1422
+ break;
1423
+ }
1424
+ case 'b': {
1425
+ enabled = 1;
1426
+ ebpf_enable_chart(EBPF_MODULE_SHM_IDX, disable_apps);
1427
+#ifdef NETDATA_INTERNAL_CHECKS
1428
+ info("EBPF enabling \"shm\" chart, because it was started with the option \"--shm\" or \"-b\".");
1429
#endif
1430
break;
1431
}
@@ -1717,6 +1746,8 @@ int main(int argc, char **argv)
1746
NULL, NULL, ebpf_modules[EBPF_MODULE_SOFTIRQ_IDX].start_routine},
1747
{"EBPF OOMKILL" , NULL, NULL, 1,
1748
NULL, NULL, ebpf_modules[EBPF_MODULE_OOMKILL_IDX].start_routine},
1749
+ {"EBPF SHM" , NULL, NULL, 1,
1750
+ NULL, NULL, ebpf_modules[EBPF_MODULE_SHM_IDX].start_routine},
1751
{NULL , NULL, NULL, 0,
1752
NULL, NULL, NULL}
1753
};
collectors/ebpf.plugin/ebpf.d.conf
+2
@@ -34,6 +34,7 @@
34
# `hardirq` : Monitor latency of serving hardware interrupt requests (hard IRQs).
35
# `oomkill` : This eBPF program creates a chart that shows which process got OOM killed and when.
36
# `process` : This eBPF program creates charts that show information about process life.
37
+# `shm` : Monitor calls for syscalls shmget, shmat, shmdt and shmctl.
38
# `socket` : This eBPF program creates charts with information about `TCP` and `UDP` functions, including the
39
# bandwidth consumed by each.
40
# `softirq` : Monitor latency of serving software interrupt requests (soft IRQs).
@@ -51,6 +52,7 @@
52
mount = yes
53
oomkill = yes
54
process = yes
55
+ shm = yes
56
socket = yes
57
softirq = yes
58
sync = yes
collectors/ebpf.plugin/ebpf.d/shm.conf
new
+22
@@ -0,0 +1,22 @@
1
+# The `ebpf load mode` option accepts the following values :
2
+# `entry` : The eBPF collector only monitors calls for the functions, and does not show charts related to errors.
3
+# `return : In the `return` mode, the eBPF collector monitors the same kernel functions as `entry`, but also creates
4
+# new charts for the return of these functions, such as errors.
5
+#
6
+# The eBPF collector also creates charts for each running application through an integration with the `apps plugin`.
7
+# If you want to disable the integration with `apps.plugin` along with the above charts, change the setting `apps` to
8
+# 'no'.
9
+#
10
+# Uncomment lines to define specific options for thread.
11
+[global]
12
+# ebpf load mode = entry
13
+# apps = yes
14
+ update every = 2
15
+# pid table size = 32768
16
+
17
+# List of monitored syscalls
18
+[syscalls]
19
+ shmget = yes
20
+ shmat = yes
21
+ shmdt = yes
22
+ shmctl = yes
collectors/ebpf.plugin/ebpf.h
+3
-1
@@ -87,7 +87,8 @@ enum ebpf_module_indexes {
87
EBPF_MODULE_FD_IDX,
88
EBPF_MODULE_HARDIRQ_IDX,
89
EBPF_MODULE_SOFTIRQ_IDX,
90
- EBPF_MODULE_OOMKILL_IDX
90
+ EBPF_MODULE_OOMKILL_IDX,
91
+ EBPF_MODULE_SHM_IDX
92
};
93
94
typedef struct ebpf_tracepoint {
@@ -115,6 +116,7 @@ typedef struct ebpf_tracepoint {
116
#define NETDATA_EBPF_MEMORY_GROUP "mem"
117
#define NETDATA_EBPF_SYSTEM_GROUP "system"
118
#define NETDATA_SYSTEM_SWAP_SUBMENU "swap"
119
+#define NETDATA_SYSTEM_IPC_SHM_SUBMENU "ipc shared memory"
120
121
// Log file
122
#define NETDATA_DEVELOPER_LOG_FILE "developer.log"
collectors/ebpf.plugin/ebpf_apps.c
+6
@@ -978,6 +978,12 @@ void cleanup_variables_from_other_threads(uint32_t pid)
978
freez(fd_pid[pid]);
979
fd_pid[pid] = NULL;
980
}
981
+
982
+ // Clean shm structure
983
+ if (shm_pid) {
984
+ freez(shm_pid[pid]);
985
+ shm_pid[pid] = NULL;
986
+ }
987
}
988
989
/**
collectors/ebpf.plugin/ebpf_apps.h
+3
@@ -14,6 +14,7 @@
14
#define NETDATA_APPS_FILE_GROUP "file_access"
15
#define NETDATA_APPS_PROCESS_GROUP "process (eBPF)"
16
#define NETDATA_APPS_NET_GROUP "net"
17
+#define NETDATA_APPS_IPC_SHM_GROUP "ipc shared memory"
18
19
#include "ebpf_process.h"
20
#include "ebpf_dcstat.h"
@@ -24,6 +25,7 @@
25
#include "ebpf_cachestat.h"
26
#include "ebpf_mount.h"
27
#include "ebpf_oomkill.h"
28
+#include "ebpf_shm.h"
29
#include "ebpf_softirq.h"
30
#include "ebpf_sync.h"
31
#include "ebpf_swap.h"
@@ -122,6 +124,7 @@ struct target {
124
netdata_publish_swap_t swap;
125
netdata_publish_vfs_t vfs;
126
netdata_fd_stat_t fd;
127
+ netdata_publish_shm_t shm;
128
129
/* These variables are not necessary for eBPF collector
130
kernel_uint_t minflt;
collectors/ebpf.plugin/ebpf_shm.c
new
+506
@@ -0,0 +1,506 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#include "ebpf.h"
4
+#include "ebpf_shm.h"
5
+
6
+static char *shm_dimension_name[NETDATA_SHM_END] = { "get", "at", "dt", "ctl" };
7
+static netdata_syscall_stat_t shm_aggregated_data[NETDATA_SHM_END];
8
+static netdata_publish_syscall_t shm_publish_aggregated[NETDATA_SHM_END];
9
+
10
+static int read_thread_closed = 1;
11
+netdata_publish_shm_t *shm_vector = NULL;
12
+
13
+static netdata_idx_t shm_hash_values[NETDATA_SHM_END];
14
+static netdata_idx_t *shm_values = NULL;
15
+
16
+netdata_publish_shm_t **shm_pid = NULL;
17
+
18
+struct config shm_config = { .first_section = NULL,
19
+ .last_section = NULL,
20
+ .mutex = NETDATA_MUTEX_INITIALIZER,
21
+ .index = { .avl_tree = { .root = NULL, .compar = appconfig_section_compare },
22
+ .rwlock = AVL_LOCK_INITIALIZER } };
23
+
24
+static ebpf_local_maps_t shm_maps[] = {{.name = "tbl_pid_shm", .internal_input = ND_EBPF_DEFAULT_PID_SIZE,
25
+ .user_input = 0,
26
+ .type = NETDATA_EBPF_MAP_RESIZABLE | NETDATA_EBPF_MAP_PID,
27
+ .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
28
+ {.name = "shm_ctrl", .internal_input = NETDATA_CONTROLLER_END,
29
+ .user_input = 0,
30
+ .type = NETDATA_EBPF_MAP_CONTROLLER,
31
+ .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
32
+ {.name = "tbl_shm", .internal_input = NETDATA_SHM_END,
33
+ .user_input = 0,
34
+ .type = NETDATA_EBPF_MAP_STATIC,
35
+ .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
36
+ {.name = NULL, .internal_input = 0, .user_input = 0}};
37
+
38
+static struct bpf_link **probe_links = NULL;
39
+static struct bpf_object *objects = NULL;
40
+
41
+struct netdata_static_thread shm_threads = {"SHM KERNEL", NULL, NULL, 1,
42
+ NULL, NULL, NULL};
43
+
44
+/*****************************************************************
45
+ * FUNCTIONS TO CLOSE THE THREAD
46
+ *****************************************************************/
47
+
48
+/**
49
+ * Clean shm structure
50
+ */
51
+void clean_shm_pid_structures() {
52
+ struct pid_stat *pids = root_of_pids;
53
+ while (pids) {
54
+ freez(shm_pid[pids->pid]);
55
+
56
+ pids = pids->next;
57
+ }
58
+}
59
+
60
+/**
61
+ * Clean up the main thread.
62
+ *
63
+ * @param ptr thread data.
64
+ */
65
+static void ebpf_shm_cleanup(void *ptr)
66
+{
67
+ ebpf_module_t *em = (ebpf_module_t *)ptr;
68
+ if (!em->enabled) {
69
+ return;
70
+ }
71
+
72
+ heartbeat_t hb;
73
+ heartbeat_init(&hb);
74
+ uint32_t tick = 2 * USEC_PER_MS;
75
+ while (!read_thread_closed) {
76
+ usec_t dt = heartbeat_next(&hb, tick);
77
+ UNUSED(dt);
78
+ }
79
+
80
+ ebpf_cleanup_publish_syscall(shm_publish_aggregated);
81
+
82
+ freez(shm_vector);
83
+ freez(shm_values);
84
+
85
+ if (probe_links) {
86
+ struct bpf_program *prog;
87
+ size_t i = 0 ;
88
+ bpf_object__for_each_program(prog, objects) {
89
+ bpf_link__destroy(probe_links[i]);
90
+ i++;
91
+ }
92
+ bpf_object__close(objects);
93
+ }
94
+}
95
+
96
+/*****************************************************************
97
+ * COLLECTOR THREAD
98
+ *****************************************************************/
99
+
100
+/**
101
+ * Apps Accumulator
102
+ *
103
+ * Sum all values read from kernel and store in the first address.
104
+ *
105
+ * @param out the vector with read values.
106
+ */
107
+static void shm_apps_accumulator(netdata_publish_shm_t *out)
108
+{
109
+ int i, end = (running_on_kernel >= NETDATA_KERNEL_V4_15) ? ebpf_nprocs : 1;
110
+ netdata_publish_shm_t *total = &out[0];
111
+ for (i = 1; i < end; i++) {
112
+ netdata_publish_shm_t *w = &out[i];
113
+ total->get += w->get;
114
+ total->at += w->at;
115
+ total->dt += w->dt;
116
+ total->ctl += w->ctl;
117
+ }
118
+}
119
+
120
+/**
121
+ * Fill PID
122
+ *
123
+ * Fill PID structures
124
+ *
125
+ * @param current_pid pid that we are collecting data
126
+ * @param out values read from hash tables;
127
+ */
128
+static void shm_fill_pid(uint32_t current_pid, netdata_publish_shm_t *publish)
129
+{
130
+ netdata_publish_shm_t *curr = shm_pid[current_pid];
131
+ if (!curr) {
132
+ curr = callocz(1, sizeof(netdata_publish_shm_t));
133
+ shm_pid[current_pid] = curr;
134
+ }
135
+
136
+ memcpy(curr, publish, sizeof(netdata_publish_shm_t));
137
+}
138
+
139
+/**
140
+ * Read APPS table
141
+ *
142
+ * Read the apps table and store data inside the structure.
143
+ */
144
+static void read_apps_table()
145
+{
146
+ netdata_publish_shm_t *cv = shm_vector;
147
+ uint32_t key;
148
+ struct pid_stat *pids = root_of_pids;
149
+ int fd = shm_maps[NETDATA_PID_SHM_TABLE].map_fd;
150
+ size_t length = sizeof(netdata_publish_shm_t)*ebpf_nprocs;
151
+ while (pids) {
152
+ key = pids->pid;
153
+
154
+ if (bpf_map_lookup_elem(fd, &key, cv)) {
155
+ pids = pids->next;
156
+ continue;
157
+ }
158
+
159
+ shm_apps_accumulator(cv);
160
+
161
+ shm_fill_pid(key, cv);
162
+
163
+ // now that we've consumed the value, zero it out in the map.
164
+ memset(cv, 0, length);
165
+ bpf_map_update_elem(fd, &key, cv, BPF_EXIST);
166
+
167
+ pids = pids->next;
168
+ }
169
+}
170
+
171
+/**
172
+* Send global charts to netdata agent.
173
+*/
174
+static void shm_send_global()
175
+{
176
+ write_begin_chart(NETDATA_EBPF_SYSTEM_GROUP, NETDATA_SHM_GLOBAL_CHART);
177
+ write_chart_dimension(
178
+ shm_publish_aggregated[NETDATA_KEY_SHMGET_CALL].dimension,
179
+ (long long) shm_hash_values[NETDATA_KEY_SHMGET_CALL]
180
+ );
181
+ write_chart_dimension(
182
+ shm_publish_aggregated[NETDATA_KEY_SHMAT_CALL].dimension,
183
+ (long long) shm_hash_values[NETDATA_KEY_SHMAT_CALL]
184
+ );
185
+ write_chart_dimension(
186
+ shm_publish_aggregated[NETDATA_KEY_SHMDT_CALL].dimension,
187
+ (long long) shm_hash_values[NETDATA_KEY_SHMDT_CALL]
188
+ );
189
+ write_chart_dimension(
190
+ shm_publish_aggregated[NETDATA_KEY_SHMCTL_CALL].dimension,
191
+ (long long) shm_hash_values[NETDATA_KEY_SHMCTL_CALL]
192
+ );
193
+ write_end_chart();
194
+}
195
+
196
+/**
197
+ * Read global counter
198
+ *
199
+ * Read the table with number of calls for all functions
200
+ */
201
+static void read_global_table()
202
+{
203
+ netdata_idx_t *stored = shm_values;
204
+ netdata_idx_t *val = shm_hash_values;
205
+ int fd = shm_maps[NETDATA_SHM_GLOBAL_TABLE].map_fd;
206
+
207
+ uint32_t i, end = NETDATA_SHM_END;
208
+ for (i = NETDATA_KEY_SHMGET_CALL; i < end; i++) {
209
+ if (!bpf_map_lookup_elem(fd, &i, stored)) {
210
+ int j;
211
+ int last = ebpf_nprocs;
212
+ netdata_idx_t total = 0;
213
+ for (j = 0; j < last; j++)
214
+ total += stored[j];
215
+
216
+ val[i] = total;
217
+ }
218
+ }
219
+}
220
+
221
+/**
222
+ * Shared memory reader thread.
223
+ *
224
+ * @param ptr It is a NULL value for this thread.
225
+ * @return It always returns NULL.
226
+ */
227
+void *ebpf_shm_read_hash(void *ptr)
228
+{
229
+ read_thread_closed = 0;
230
+
231
+ heartbeat_t hb;
232
+ heartbeat_init(&hb);
233
+
234
+ ebpf_module_t *em = (ebpf_module_t *)ptr;
235
+ usec_t step = NETDATA_SHM_SLEEP_MS * em->update_time;
236
+ while (!close_ebpf_plugin) {
237
+ usec_t dt = heartbeat_next(&hb, step);
238
+ (void)dt;
239
+
240
+ read_global_table();
241
+ }
242
+
243
+ read_thread_closed = 1;
244
+ return NULL;
245
+}
246
+
247
+/**
248
+ * Sum values for all targets.
249
+ */
250
+static void ebpf_shm_sum_pids(netdata_publish_shm_t *shm, struct pid_on_target *root)
251
+{
252
+ while (root) {
253
+ int32_t pid = root->pid;
254
+ netdata_publish_shm_t *w = shm_pid[pid];
255
+ if (w) {
256
+ shm->get += w->get;
257
+ shm->at += w->at;
258
+ shm->dt += w->dt;
259
+ shm->ctl += w->ctl;
260
+
261
+ // reset for next collection.
262
+ w->get = 0;
263
+ w->at = 0;
264
+ w->dt = 0;
265
+ w->ctl = 0;
266
+ }
267
+ root = root->next;
268
+ }
269
+}
270
+
271
+/**
272
+ * Send data to Netdata calling auxiliar functions.
273
+ *
274
+ * @param root the target list.
275
+*/
276
+void ebpf_shm_send_apps_data(struct target *root)
277
+{
278
+ struct target *w;
279
+ for (w = root; w; w = w->next) {
280
+ if (unlikely(w->exposed && w->processes)) {
281
+ ebpf_shm_sum_pids(&w->shm, w->root_pid);
282
+ }
283
+ }
284
+
285
+ write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SHMGET_CHART);
286
+ for (w = root; w; w = w->next) {
287
+ if (unlikely(w->exposed && w->processes)) {
288
+ write_chart_dimension(w->name, (long long) w->shm.get);
289
+ }
290
+ }
291
+ write_end_chart();
292
+
293
+ write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SHMAT_CHART);
294
+ for (w = root; w; w = w->next) {
295
+ if (unlikely(w->exposed && w->processes)) {
296
+ write_chart_dimension(w->name, (long long) w->shm.at);
297
+ }
298
+ }
299
+ write_end_chart();
300
+
301
+ write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SHMDT_CHART);
302
+ for (w = root; w; w = w->next) {
303
+ if (unlikely(w->exposed && w->processes)) {
304
+ write_chart_dimension(w->name, (long long) w->shm.dt);
305
+ }
306
+ }
307
+ write_end_chart();
308
+
309
+ write_begin_chart(NETDATA_APPS_FAMILY, NETDATA_SHMCTL_CHART);
310
+ for (w = root; w; w = w->next) {
311
+ if (unlikely(w->exposed && w->processes)) {
312
+ write_chart_dimension(w->name, (long long) w->shm.ctl);
313
+ }
314
+ }
315
+ write_end_chart();
316
+}
317
+
318
+/**
319
+* Main loop for this collector.
320
+*/
321
+static void shm_collector(ebpf_module_t *em)
322
+{
323
+ shm_threads.thread = mallocz(sizeof(netdata_thread_t));
324
+ shm_threads.start_routine = ebpf_shm_read_hash;
325
+
326
+ netdata_thread_create(
327
+ shm_threads.thread,
328
+ shm_threads.name,
329
+ NETDATA_THREAD_OPTION_JOINABLE,
330
+ ebpf_shm_read_hash,
331
+ em
332
+ );
333
+
334
+ int apps = em->apps_charts;
335
+ while (!close_ebpf_plugin) {
336
+ pthread_mutex_lock(&collect_data_mutex);
337
+ pthread_cond_wait(&collect_data_cond_var, &collect_data_mutex);
338
+
339
+ if (apps) {
340
+ read_apps_table();
341
+ }
342
+
343
+ pthread_mutex_lock(&lock);
344
+
345
+ shm_send_global();
346
+
347
+ if (apps) {
348
+ ebpf_shm_send_apps_data(apps_groups_root_target);
349
+ }
350
+
351
+ pthread_mutex_unlock(&lock);
352
+ pthread_mutex_unlock(&collect_data_mutex);
353
+ }
354
+}
355
+
356
+/*****************************************************************
357
+ * INITIALIZE THREAD
358
+ *****************************************************************/
359
+
360
+/**
361
+ * Create apps charts
362
+ *
363
+ * Call ebpf_create_chart to create the charts on apps submenu.
364
+ *
365
+ * @param em a pointer to the structure with the default values.
366
+ */
367
+void ebpf_shm_create_apps_charts(struct ebpf_module *em, void *ptr)
368
+{
369
+ UNUSED(em);
370
+
371
+ struct target *root = ptr;
372
+ ebpf_create_charts_on_apps(NETDATA_SHMGET_CHART,
373
+ "Calls to syscall <code>shmget(2)</code>.",
374
+ EBPF_COMMON_DIMENSION_CALL,
375
+ NETDATA_APPS_IPC_SHM_GROUP,
376
+ NETDATA_EBPF_CHART_TYPE_STACKED,
377
+ 20191,
378
+ ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
379
+ root, NETDATA_EBPF_MODULE_NAME_SHM);
380
+
381
+ ebpf_create_charts_on_apps(NETDATA_SHMAT_CHART,
382
+ "Calls to syscall <code>shmat(2)</code>.",
383
+ EBPF_COMMON_DIMENSION_CALL,
384
+ NETDATA_APPS_IPC_SHM_GROUP,
385
+ NETDATA_EBPF_CHART_TYPE_STACKED,
386
+ 20192,
387
+ ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
388
+ root, NETDATA_EBPF_MODULE_NAME_SHM);
389
+
390
+ ebpf_create_charts_on_apps(NETDATA_SHMDT_CHART,
391
+ "Calls to syscall <code>shmdt(2)</code>.",
392
+ EBPF_COMMON_DIMENSION_CALL,
393
+ NETDATA_APPS_IPC_SHM_GROUP,
394
+ NETDATA_EBPF_CHART_TYPE_STACKED,
395
+ 20193,
396
+ ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
397
+ root, NETDATA_EBPF_MODULE_NAME_SHM);
398
+
399
+ ebpf_create_charts_on_apps(NETDATA_SHMCTL_CHART,
400
+ "Calls to syscall <code>shmctl(2)</code>.",
401
+ EBPF_COMMON_DIMENSION_CALL,
402
+ NETDATA_APPS_IPC_SHM_GROUP,
403
+ NETDATA_EBPF_CHART_TYPE_STACKED,
404
+ 20194,
405
+ ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX],
406
+ root, NETDATA_EBPF_MODULE_NAME_SHM);
407
+}
408
+
409
+/**
410
+ * Allocate vectors used with this thread.
411
+ *
412
+ * We are not testing the return, because callocz does this and shutdown the software
413
+ * case it was not possible to allocate.
414
+ *
415
+ * @param length is the length for the vectors used inside the collector.
416
+ */
417
+static void ebpf_shm_allocate_global_vectors()
418
+{
419
+ shm_pid = callocz((size_t)pid_max, sizeof(netdata_publish_shm_t *));
420
+ shm_vector = callocz((size_t)ebpf_nprocs, sizeof(netdata_publish_shm_t));
421
+
422
+ shm_values = callocz((size_t)ebpf_nprocs, sizeof(netdata_idx_t));
423
+
424
+ memset(shm_hash_values, 0, sizeof(shm_hash_values));
425
+}
426
+
427
+/*****************************************************************
428
+ * MAIN THREAD
429
+ *****************************************************************/
430
+
431
+/**
432
+ * Create global charts
433
+ *
434
+ * Call ebpf_create_chart to create the charts for the collector.
435
+ */
436
+static void ebpf_create_shm_charts()
437
+{
438
+ ebpf_create_chart(
439
+ NETDATA_EBPF_SYSTEM_GROUP,
440
+ NETDATA_SHM_GLOBAL_CHART,
441
+ "Calls to shared memory system calls.",
442
+ EBPF_COMMON_DIMENSION_CALL,
443
+ NETDATA_SYSTEM_IPC_SHM_SUBMENU,
444
+ NULL,
445
+ NETDATA_EBPF_CHART_TYPE_LINE,
446
+ NETDATA_CHART_PRIO_SYSTEM_IPC_SHARED_MEM_CALLS,
447
+ ebpf_create_global_dimension,
448
+ shm_publish_aggregated,
449
+ NETDATA_SHM_END,
450
+ NETDATA_EBPF_MODULE_NAME_SHM
451
+ );
452
+
453
+ fflush(stdout);
454
+}
455
+
456
+/**
457
+ * Shared memory thread.
458
+ *
459
+ * @param ptr a pointer to `struct ebpf_module`
460
+ * @return It always return NULL
461
+ */
462
+void *ebpf_shm_thread(void *ptr)
463
+{
464
+ netdata_thread_cleanup_push(ebpf_shm_cleanup, ptr);
465
+
466
+ ebpf_module_t *em = (ebpf_module_t *)ptr;
467
+ em->maps = shm_maps;
468
+
469
+ ebpf_update_pid_table(&shm_maps[NETDATA_PID_SHM_TABLE], em);
470
+
471
+ if (!em->enabled) {
472
+ goto endshm;
473
+ }
474
+
475
+ probe_links = ebpf_load_program(ebpf_plugin_dir, em, kernel_string, &objects);
476
+ if (!probe_links) {
477
+ goto endshm;
478
+ }
479
+
480
+ ebpf_shm_allocate_global_vectors();
481
+
482
+ int algorithms[NETDATA_SHM_END] = {
483
+ NETDATA_EBPF_INCREMENTAL_IDX,
484
+ NETDATA_EBPF_INCREMENTAL_IDX,
485
+ NETDATA_EBPF_INCREMENTAL_IDX,
486
+ NETDATA_EBPF_INCREMENTAL_IDX
487
+ };
488
+ ebpf_global_labels(
489
+ shm_aggregated_data,
490
+ shm_publish_aggregated,
491
+ shm_dimension_name,
492
+ shm_dimension_name,
493
+ algorithms,
494
+ NETDATA_SHM_END
495
+ );
496
+
497
+ pthread_mutex_lock(&lock);
498
+ ebpf_create_shm_charts();
499
+ pthread_mutex_unlock(&lock);
500
+
501
+ shm_collector(em);
502
+
503
+endshm:
504
+ netdata_thread_cleanup_pop(1);
505
+ return NULL;
506
+}
collectors/ebpf.plugin/ebpf_shm.h
new
+52
@@ -0,0 +1,52 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#ifndef NETDATA_EBPF_SHM_H
4
+#define NETDATA_EBPF_SHM_H 1
5
+
6
+// Module name
7
+#define NETDATA_EBPF_MODULE_NAME_SHM "shm"
8
+
9
+#define NETDATA_SHM_SLEEP_MS 850000ULL
10
+
11
+// charts
12
+#define NETDATA_SHM_GLOBAL_CHART "shared_memory_calls"
13
+#define NETDATA_SHMGET_CHART "shmget_call"
14
+#define NETDATA_SHMAT_CHART "shmat_call"
15
+#define NETDATA_SHMDT_CHART "shmdt_call"
16
+#define NETDATA_SHMCTL_CHART "shmctl_call"
17
+
18
+// configuration file
19
+#define NETDATA_DIRECTORY_SHM_CONFIG_FILE "shm.conf"
20
+
21
+typedef struct netdata_publish_shm {
22
+ uint64_t get;
23
+ uint64_t at;
24
+ uint64_t dt;
25
+ uint64_t ctl;
26
+} netdata_publish_shm_t;
27
+
28
+enum shm_tables {
29
+ NETDATA_PID_SHM_TABLE,
30
+ NETDATA_SHM_CONTROLLER,
31
+ NETDATA_SHM_GLOBAL_TABLE
32
+};
33
+
34
+enum shm_counters {
35
+ NETDATA_KEY_SHMGET_CALL,
36
+ NETDATA_KEY_SHMAT_CALL,
37
+ NETDATA_KEY_SHMDT_CALL,
38
+ NETDATA_KEY_SHMCTL_CALL,
39
+
40
+ // Keep this as last and don't skip numbers as it is used as element counter
41
+ NETDATA_SHM_END
42
+};
43
+
44
+extern netdata_publish_shm_t **shm_pid;
45
+
46
+extern void *ebpf_shm_thread(void *ptr);
47
+extern void ebpf_shm_create_apps_charts(struct ebpf_module *em, void *ptr);
48
+extern void clean_shm_pid_structures();
49
+
50
+extern struct config shm_config;
51
+
52
+#endif
packaging/ebpf.checksums
+3
-3
@@ -1,3 +1,3 @@
1
-7db767f09bd422c2e15c7bd8af47eea9c32f3c435a1166e02ac65abad36fd6e4 netdata-kernel-collector-glibc-v0.8.0.tar.xz
2
-705da99b6f7d782f1eca1924b12629826ae15844ab781555d7849a9baa682e50 netdata-kernel-collector-musl-v0.8.0.tar.xz
3
-13d48b50786d007cf10e35ce7b9641935b5df684d2637f122a7a51651dd5c8a6 netdata-kernel-collector-static-v0.8.0.tar.xz
1
+f8e89d3a37b49f2b14d66dace463545e19bbcb5f486f0ef525d8e57b4acf809b netdata-kernel-collector-glibc-v0.8.1.tar.xz
2
+094d4a9b05463031feb432cdaf599570e77df226ea743ee16b11178de00ca930 netdata-kernel-collector-musl-v0.8.1.tar.xz
3
+2994127a98ac86f0028c8242ba41a0ccc69786c076cc236d27b187ea2d38876a netdata-kernel-collector-static-v0.8.1.tar.xz
packaging/ebpf.version
+1
-1
@@ -1 +1 @@
1
-v0.8.0
1
+v0.8.1
web/gui/dashboard_info.js
+20
@@ -1169,6 +1169,10 @@ netdataDashboard.context = {
1169
'The run-time limit on the maximum shared memory segment size that can be created is specified in <code>/proc/sys/kernel/shmmax</code> file.'
1170
},
1171
1172
+ 'system.shared_memory_calls': {
1173
+ info: 'Monitor calls to functions <code>shmget</code>, <code>shmat</code>, <code>shmdt</code>, and <code>shmctl</code>. When integration with apps is <a href="https://learn.netdata.cloud/guides/troubleshoot/monitor-debug-applications-ebpf" target="_blank">enabled</a>, Netdata also shows shared memory system call usage <a href="#menu_apps_submenu_ipc_shared_memory">per application</a>.'
1174
+ },
1175
+
1176
'system.message_queue_messages': {
1177
info: 'Number of messages that are currently present in System V IPC message queues.'
1178
},
@@ -4565,6 +4569,22 @@ netdataDashboard.context = {
4569
info: 'The function <code>swap_writepage</code> is called when the kernel writes a page to swap memory.'
4570
},
4571
4572
+ 'apps.shmget_call': {
4573
+ info: 'Number of times the syscall <code>shmget</code> is called. Netdata also gives a summary for these charts in <a href="#menu_system_submenu_ipc_shared_memory">System overview</a>.'
4574
+ },
4575
+
4576
+ 'apps.shmat_call': {
4577
+ info: 'Number of times the syscall <code>shmat</code> is called.'
4578
+ },
4579
+
4580
+ 'apps.shmdt_call': {
4581
+ info: 'Number of times the syscall <code>shmdt</code> is called.'
4582
+ },
4583
+
4584
+ 'apps.shmctl_call': {
4585
+ info: 'Number of times the syscall <code>shmctl</code> is called.'
4586
+ },
4587
+
4588
// ------------------------------------------------------------------------
4589
// ACLK Internal Stats
4590
'netdata.aclk_status': {