@cryptotaxi247 / netdata-1 / commits / 5e91a7bc0

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': {