@cryptotaxi247 / netdata-1 / commits / 588096c6b

Debugfs collector (#15017)

Co-authored-by: Fotis Voutsas <fotis@netdata.cloud> Co-authored-by: Austin S. Hemmelgarn <ahferroin7@gmail.com> Co-authored-by: ilyam8 <ilya@netdata.cloud>

thiagoftsm committed May 15, 2023 at 16:06 UTC 588096c6b682ec467d85656abab65d77f74e5755
24 files changed +1039 -4
.github/labeler.yml
+4
@@ -78,6 +78,10 @@ collectors/cups:
78 - collectors/cups.plugin/*
79 - collectors/cups.plugin/**/*
80
81 +collectors/debugfs:
82 + - collectors/debugfs.plugin/*
83 + - collectors/debugfs.plugin/**/*
84 +
85 collectors/diskspace:
86 - collectors/diskspace.plugin/*
87 - collectors/diskspace.plugin/**/*
.gitignore
+3
@@ -74,6 +74,9 @@ collectors/ebpf.plugin/reset_netdata_trace.sh
74 !ebpf.plugin/
75 collectors/ebpf.plugin/includes/
76
77 +debugfs.plugin
78 +!debugfs.plugin/
79 +
80 # protoc generated files
81 *.pb.cc
82 *.pb.h
CMakeLists.txt
+22
@@ -507,6 +507,13 @@ target_include_directories(libnetdata BEFORE PUBLIC ${GENERATED_CONFIG_H_DIR})
507 set(APPS_PLUGIN_FILES
508 collectors/apps.plugin/apps_plugin.c)
509
510 +set(DEBUGFS_PLUGIN_FILES
511 + collectors/debugfs.plugin/debugfs_plugin.c
512 + collectors/debugfs.plugin/debugfs_plugin.h
513 + collectors/debugfs.plugin/debugfs_extfrag.c
514 + collectors/debugfs.plugin/debugfs_zswap.c
515 + )
516 +
517 set(FREEBSD_PLUGIN_FILES
518 collectors/freebsd.plugin/plugin_freebsd.c
519 collectors/freebsd.plugin/plugin_freebsd.h
@@ -1363,6 +1370,21 @@ target_include_directories(netdatacli BEFORE PUBLIC ${GENERATED_CONFIG_H_DIR})
1370 target_compile_options(netdatacli PUBLIC ${NETDATA_COMMON_CFLAGS})
1371
1372
1373 +# -----------------------------------------------------------------------------
1374 +# debugfs.plugin
1375 +
1376 +IF(ENABLE_PLUGIN_DEBUGFS)
1377 + message(STATUS "debugfs.plugin: enabled")
1378 + add_executable(debugfs.plugin ${GENERATED_CONFIG_H} ${DEBUGFS_PLUGIN_FILES})
1379 + target_link_libraries (debugfs.plugin libnetdata ${NETDATA_COMMON_LIBRARIES} ${CAP_LIBRARIES})
1380 + target_include_directories(debugfs.plugin PUBLIC ${NETDATA_COMMON_INCLUDE_DIRS} ${CAP_INCLUDE_DIRS})
1381 + target_include_directories(debugfs.plugin BEFORE PUBLIC ${GENERATED_CONFIG_H_DIR})
1382 + target_compile_options(debugfs.plugin PUBLIC ${NETDATA_COMMON_CFLAGS} ${CAP_CFLAGS_OTHER})
1383 +ELSE()
1384 + message(STATUS "debugfs.plugin: disabled")
1385 +ENDIF()
1386 +
1387 +
1388 # -----------------------------------------------------------------------------
1389 # apps.plugin
1390
Makefile.am
+17
@@ -212,6 +212,14 @@ APPS_PLUGIN_FILES = \
212 $(LIBNETDATA_FILES) \
213 $(NULL)
214
215 +DEBUGFS_PLUGIN_FILES = \
216 + collectors/debugfs.plugin/debugfs_plugin.c \
217 + collectors/debugfs.plugin/debugfs_plugin.h \
218 + collectors/debugfs.plugin/debugfs_extfrag.c \
219 + collectors/debugfs.plugin/debugfs_zswap.c \
220 + $(LIBNETDATA_FILES) \
221 + $(NULL)
222 +
223 FREEBSD_PLUGIN_FILES = \
224 collectors/freebsd.plugin/plugin_freebsd.c \
225 collectors/freebsd.plugin/plugin_freebsd.h \
@@ -1168,6 +1176,15 @@ if ENABLE_PLUGIN_APPS
1176 $(NULL)
1177 endif
1178
1179 +if ENABLE_PLUGIN_DEBUGFS
1180 + plugins_PROGRAMS += debugfs.plugin
1181 + debugfs_plugin_SOURCES = $(DEBUGFS_PLUGIN_FILES)
1182 + debugfs_plugin_LDADD = \
1183 + $(NETDATA_COMMON_LIBS) \
1184 + $(OPTIONAL_LIBCAP_LIBS) \
1185 + $(NULL)
1186 +endif
1187 +
1188 if ENABLE_PLUGIN_CGROUP_NETWORK
1189 plugins_PROGRAMS += cgroup-network
1190 cgroup_network_SOURCES = $(CGROUP_NETWORK_FILES)
collectors/Makefile.am
+1
@@ -8,6 +8,7 @@ SUBDIRS = \
8 cgroups.plugin \
9 charts.d.plugin \
10 cups.plugin \
11 + debugfs.plugin \
12 diskspace.plugin \
13 timex.plugin \
14 ioping.plugin \
collectors/all.h
+10
@@ -24,8 +24,17 @@
24 #define NETDATA_CHART_PRIO_SYSTEM_PGPGIO 151
25 #define NETDATA_CHART_PRIO_SYSTEM_RAM 200
26 #define NETDATA_CHART_PRIO_SYSTEM_SWAP 201
27 +#define NETDATA_CHART_PRIO_SYSTEM_SWAP_CALLS 202
28 #define NETDATA_CHART_PRIO_SYSTEM_SWAPIO 250
29 #define NETDATA_CHART_PRIO_SYSTEM_ZSWAPIO 300
30 +#define NETDATA_CHART_PRIO_SYSTEM_ZSWAP_COMPRESS_RATIO 301
31 +#define NETDATA_CHART_PRIO_SYSTEM_ZSWAP_POOL_TOT_SIZE 302
32 +#define NETDATA_CHART_PRIO_SYSTEM_ZSWAP_STORED_PAGE 303
33 +#define NETDATA_CHART_PRIO_SYSTEM_ZSWAP_REJECTS 304
34 +#define NETDATA_CHART_PRIO_SYSTEM_ZSWAP_POOL_LIM_HIT 305
35 +#define NETDATA_CHART_PRIO_SYSTEM_ZSWAP_WRT_BACK_PAGES 306
36 +#define NETDATA_CHART_PRIO_SYSTEM_ZSWAP_SAME_FILL_PAGE 307
37 +#define NETDATA_CHART_PRIO_SYSTEM_ZSWAP_DUPP_ENTRY 308
38 #define NETDATA_CHART_PRIO_SYSTEM_NET 500
39 #define NETDATA_CHART_PRIO_SYSTEM_IPV4 500 // freebsd only
40 #define NETDATA_CHART_PRIO_SYSTEM_IP 501
@@ -103,6 +112,7 @@
112 #define NETDATA_CHART_PRIO_MEM_ZRAM_SAVINGS 1601
113 #define NETDATA_CHART_PRIO_MEM_ZRAM_RATIO 1602
114 #define NETDATA_CHART_PRIO_MEM_ZRAM_EFFICIENCY 1603
115 +#define NETDATA_CHART_PRIO_MEM_FRAGMENTATION 1700
116
117 // Disks
118
collectors/apps.plugin/apps_groups.conf
+1
@@ -89,6 +89,7 @@ ioping: ioping
89 go.d.plugin: *go.d.plugin*
90 slabinfo.plugin: slabinfo.plugin
91 ebpf.plugin: *ebpf.plugin*
92 +debugfs.plugin: *debugfs.plugin*
93
94 # agent-service-discovery
95 agent_sd: agent_sd
collectors/debugfs.plugin/Makefile.am new
+9
@@ -0,0 +1,9 @@
1 +# SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +AUTOMAKE_OPTIONS = subdir-objects
4 +MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
5 +
6 +dist_noinst_DATA = \
7 + README.md \
8 + $(NULL)
9 +
collectors/debugfs.plugin/README.md new
+65
@@ -0,0 +1,65 @@
1 +# OS provided metrics (debugfs.plugin)
2 +
3 +`debugfs.plugin` gathers metrics from the `/sys/kernel/debug` folder on Linux
4 +systems. [Debugfs](https://docs.kernel.org/filesystems/debugfs.html) exists as an easy way for kernel developers to
5 +make information available to user space.
6 +
7 +This plugin
8 +is [external](https://github.com/netdata/netdata/tree/master/collectors#collector-architecture-and-terminology),
9 +the netdata daemon spawns it as a long-running independent process.
10 +
11 +In detail, it collects metrics from:
12 +
13 +- `/sys/kernel/debug/extfrag` (Memory fragmentation index for each order and zone).
14 +- `/sys/kernel/debug/zswap` ([Zswap](https://www.kernel.org/doc/Documentation/vm/zswap.txt) performance statistics).
15 +
16 +## Prerequisites
17 +
18 +### Permissions
19 +
20 +> No user action required.
21 +
22 +The debugfs root directory is accessible only to the root user by default. Netdata
23 +uses [Linux Capabilities](https://man7.org/linux/man-pages/man7/capabilities.7.html) to give the plugin access
24 +to debugfs. `CAP_DAC_READ_SEARCH` is added automatically during installation. This capability allows bypassing file read
25 +permission checks and directory read and execute permission checks. If file capabilities are not usable, then the plugin is instead installed with the SUID bit set in permissions so that it runs as root.
26 +
27 +## Metrics
28 +
29 +| Metric | Scope | Dimensions | Units | Labels |
30 +|-------------------------------------|:---------:|:---------------------------------------------------------------------------------------:|:------------:|:---------:|
31 +| mem.fragmentation_index_dma | numa node | order0, order1, order2, order3, order4, order5, order6, order7, order8, order9, order10 | index | numa_node |
32 +| mem.fragmentation_index_dma32 | numa node | order0, order1, order2, order3, order4, order5, order6, order7, order8, order9, order10 | index | numa_node |
33 +| mem.fragmentation_index_normal | numa node | order0, order1, order2, order3, order4, order5, order6, order7, order8, order9, order10 | index | numa_node |
34 +| system.zswap_pool_compression_ratio | | compression_ratio | ratio | |
35 +| system.zswap_pool_compressed_size | | compressed_size | bytes | |
36 +| system.zswap_pool_raw_size | | uncompressed_size | bytes | |
37 +| system.zswap_rejections | | compress_poor, kmemcache_fail, alloc_fail, reclaim_fail | rejections/s | |
38 +| system.zswap_pool_limit_hit | | limit | events/s | |
39 +| system.zswap_written_back_raw_bytes | | written_back | bytes/s | |
40 +| system.zswap_same_filled_raw_size | | same_filled | bytes | |
41 +| system.zswap_duplicate_entry | | entries | entries/s | |
42 +
43 +## Troubleshooting
44 +
45 +To troubleshoot issues with the collector, run the `debugfs.plugin` in the terminal. The output
46 +should give you clues as to why the collector isn't working.
47 +
48 +- Navigate to the `plugins.d` directory, usually at `/usr/libexec/netdata/plugins.d/`. If that's not the case on
49 + your system, open `netdata.conf` and look for the `plugins` setting under `[directories]`.
50 +
51 + ```bash
52 + cd /usr/libexec/netdata/plugins.d/
53 + ```
54 +
55 +- Switch to the `netdata` user.
56 +
57 + ```bash
58 + sudo -u netdata -s
59 + ```
60 +
61 +- Run the `debugfs.plugin` to debug the collector:
62 +
63 + ```bash
64 + ./debugfs.plugin
65 + ```
collectors/debugfs.plugin/debugfs_extfrag.c new
+123
@@ -0,0 +1,123 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "debugfs_plugin.h"
4 +
5 +#define NETDATA_ORDER_FRAGMENTATION 11
6 +
7 +static char *orders[NETDATA_ORDER_FRAGMENTATION] = { "order0", "order1", "order2", "order3", "order4",
8 + "order5", "order6", "order7", "order8", "order9",
9 + "order10"
10 +};
11 +
12 +static struct netdata_extrafrag {
13 + char *node_zone;
14 + uint32_t hash;
15 +
16 + char *id;
17 +
18 + collected_number orders[NETDATA_ORDER_FRAGMENTATION];
19 +
20 + struct netdata_extrafrag *next;
21 +} *netdata_extrafrags_root = NULL;
22 +
23 +static struct netdata_extrafrag *find_or_create_extrafrag(const char *name)
24 +{
25 + struct netdata_extrafrag *extrafrag;
26 + uint32_t hash = simple_hash(name);
27 +
28 + // search it, from beginning to the end
29 + for (extrafrag = netdata_extrafrags_root ; extrafrag ; extrafrag = extrafrag->next) {
30 + if (unlikely(hash == extrafrag->hash && !strcmp(name, extrafrag->node_zone))) {
31 + return extrafrag;
32 + }
33 + }
34 +
35 + extrafrag = callocz(1, sizeof(struct netdata_extrafrag));
36 + extrafrag->node_zone = strdupz(name);
37 + extrafrag->hash = hash;
38 +
39 + if (netdata_extrafrags_root) {
40 + struct netdata_extrafrag *last_node;
41 + for (last_node = netdata_extrafrags_root; last_node->next ; last_node = last_node->next);
42 +
43 + last_node->next = extrafrag;
44 + } else
45 + netdata_extrafrags_root = extrafrag;
46 +
47 +
48 + return extrafrag;
49 +}
50 +
51 +static void extfrag_send_chart(char *chart_id, collected_number *values)
52 +{
53 + int i;
54 + fprintf(stdout, "BEGIN mem.fragmentation_index_%s\n", chart_id);
55 + for (i = 0; i < NETDATA_ORDER_FRAGMENTATION; i++) {
56 + fprintf(stdout, "SET %s = %lld\n", orders[i], values[i]);
57 + }
58 + fprintf(stdout, "END\n");
59 + fflush(stdout);
60 +}
61 +
62 +int do_debugfs_extfrag(int update_every, const char *name) {
63 + static procfile *ff = NULL;
64 + static int chart_order = NETDATA_CHART_PRIO_MEM_FRAGMENTATION;
65 +
66 + if (unlikely(!ff)) {
67 + char filename[FILENAME_MAX + 1];
68 + snprintfz(filename,
69 + FILENAME_MAX,
70 + "%s%s",
71 + netdata_configured_host_prefix,
72 + "/sys/kernel/debug/extfrag/extfrag_index");
73 +
74 + ff = procfile_open(filename, " \t,", PROCFILE_FLAG_DEFAULT);
75 + if (unlikely(!ff)) return 1;
76 + }
77 +
78 + ff = procfile_readall(ff);
79 + if (unlikely(!ff)) return 1;
80 +
81 + size_t l, i, j, lines = procfile_lines(ff);
82 + for (l = 0; l < lines; l++) {
83 + char chart_id[64];
84 + char zone_lowercase[32];
85 + if (unlikely(procfile_linewords(ff, l) < 15)) continue;
86 + char *zone = procfile_lineword(ff, l, 3);
87 + strncpyz(zone_lowercase, zone, 31);
88 + debugfs2lower(zone_lowercase);
89 +
90 + char *id = procfile_lineword(ff, l, 1);
91 + snprintfz(chart_id, 63, "node_%s_%s", id, zone_lowercase);
92 + debugfs2lower(chart_id);
93 +
94 + struct netdata_extrafrag *extrafrag = find_or_create_extrafrag(chart_id);
95 + collected_number *line_orders = extrafrag->orders;
96 + for (i = 4, j = 0 ; i < 15; i++, j++) {
97 + NETDATA_DOUBLE value = str2ndd(procfile_lineword(ff, l, i), NULL);
98 + line_orders[j] = (collected_number) (value * 1000.0);
99 + }
100 +
101 + if (unlikely(!extrafrag->id)) {
102 + extrafrag->id = extrafrag->node_zone;
103 + fprintf(
104 + stdout,
105 + "CHART mem.fragmentation_index_%s '' 'Memory fragmentation index for each order' 'index' 'fragmentation' 'mem.fragmentation_index_%s' 'line' %d %d '' 'debugfs.plugin' '%s'\n",
106 + extrafrag->node_zone,
107 + zone_lowercase,
108 + chart_order++, // FIXME: the same zones must have the same order
109 + update_every,
110 + name);
111 + for (i = 0; i < NETDATA_ORDER_FRAGMENTATION; i++) {
112 + fprintf(stdout, "DIMENSION '%s' '%s' absolute 1 1000 ''\n", orders[i], orders[i]);
113 + }
114 + fprintf(stdout,
115 + "CLABEL 'numa_node' 'node%s' 1\n"
116 + "CLABEL_COMMIT\n",
117 + id);
118 + }
119 + extfrag_send_chart(chart_id, line_orders);
120 + }
121 +
122 + return 0;
123 +}
collectors/debugfs.plugin/debugfs_plugin.c new
+244
@@ -0,0 +1,244 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "debugfs_plugin.h"
4 +#include "libnetdata/required_dummies.h"
5 +
6 +static char *user_config_dir = CONFIG_DIR;
7 +static char *stock_config_dir = LIBCONFIG_DIR;
8 +
9 +static int update_every = 1;
10 +
11 +static struct debugfs_module {
12 + const char *name;
13 +
14 + int enabled;
15 +
16 + int (*func)(int update_every, const char *name);
17 +} debugfs_modules[] = {
18 + // Memory Fragmentation
19 + { .name = "/sys/kernel/debug/extfrag", .enabled = CONFIG_BOOLEAN_YES,
20 + .func = do_debugfs_extfrag},
21 + { .name = "/sys/kernel/debug/zswap", .enabled = CONFIG_BOOLEAN_YES,
22 + .func = do_debugfs_zswap},
23 +
24 + // The terminator
25 + { .name = NULL, .enabled = CONFIG_BOOLEAN_NO, .func = NULL}
26 +};
27 +
28 +#ifdef HAVE_CAPABILITY
29 +static int debugfs_check_capabilities()
30 +{
31 + cap_t caps = cap_get_proc();
32 + if (!caps) {
33 + error("Cannot get current capabilities.");
34 + return 0;
35 + }
36 +
37 + int ret = 1;
38 + cap_flag_value_t cfv = CAP_CLEAR;
39 + if (cap_get_flag(caps, CAP_DAC_READ_SEARCH, CAP_EFFECTIVE, &cfv) == -1) {
40 + error("Cannot find if CAP_DAC_READ_SEARCH is effective.");
41 + ret = 0;
42 + } else {
43 + if (cfv != CAP_SET) {
44 + error("debugfs.plugin should run with CAP_DAC_READ_SEARCH.");
45 + ret = 0;
46 + }
47 + }
48 + cap_free(caps);
49 +
50 + return ret;
51 +}
52 +#else
53 +static int debugfs_check_capabilities()
54 +{
55 + return 0;
56 +}
57 +#endif
58 +
59 +// TODO: This is a function used by 3 different collector, we should do it global (next PR)
60 +static int debugfs_am_i_running_as_root()
61 +{
62 + uid_t uid = getuid(), euid = geteuid();
63 +
64 + if (uid == 0 || euid == 0) {
65 + return 1;
66 + }
67 +
68 + return 0;
69 +}
70 +
71 +void debugfs2lower(char *name)
72 +{
73 + while (*name) {
74 + *name = tolower(*name);
75 + name++;
76 + }
77 +}
78 +
79 +// Consiidering our goal to redce binaries, I preferred to copy function, instead to force link with unecessary libs
80 +const char *debugfs_rrdset_type_name(RRDSET_TYPE chart_type) {
81 + switch(chart_type) {
82 + case RRDSET_TYPE_LINE:
83 + default:
84 + return RRDSET_TYPE_LINE_NAME;
85 +
86 + case RRDSET_TYPE_AREA:
87 + return RRDSET_TYPE_AREA_NAME;
88 +
89 + case RRDSET_TYPE_STACKED:
90 + return RRDSET_TYPE_STACKED_NAME;
91 + }
92 +}
93 +
94 +const char *debugfs_rrd_algorithm_name(RRD_ALGORITHM algorithm) {
95 + switch(algorithm) {
96 + case RRD_ALGORITHM_ABSOLUTE:
97 + default:
98 + return RRD_ALGORITHM_ABSOLUTE_NAME;
99 +
100 + case RRD_ALGORITHM_INCREMENTAL:
101 + return RRD_ALGORITHM_INCREMENTAL_NAME;
102 +
103 + case RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL:
104 + return RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL_NAME;
105 +
106 + case RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL:
107 + return RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL_NAME;
108 + }
109 +}
110 +
111 +int debugfs_check_sys_permission() {
112 + int ret = 0;
113 +
114 + char filename[FILENAME_MAX + 1];
115 +
116 + snprintfz(filename, FILENAME_MAX, "%s/sys/kernel/debug/extfrag/extfrag_index", netdata_configured_host_prefix);
117 +
118 + procfile *ff = procfile_open(filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
119 + if(!ff) goto dcsp_cleanup;
120 +
121 + ff = procfile_readall(ff);
122 + if(!ff) goto dcsp_cleanup;
123 +
124 + ret = 1;
125 +
126 +dcsp_cleanup:
127 + if (!ret)
128 + perror("Cannot open /sys/kernel/debug/extfrag/extfrag_index file");
129 + procfile_close(ff);
130 + return ret;
131 +}
132 +
133 +static void debugfs_parse_args(int argc, char **argv)
134 +{
135 + int i, freq = 0;
136 + for(i = 1; i < argc; i++) {
137 + if(!freq) {
138 + int n = (int)str2l(argv[i]);
139 + if(n > 0) {
140 + freq = n;
141 + continue;
142 + }
143 + }
144 +
145 + if(strcmp("test-permissions", argv[i]) == 0 || strcmp("-t", argv[i]) == 0) {
146 + if(!debugfs_check_sys_permission()) {
147 + exit(2);
148 + }
149 + printf("OK\n");
150 + exit(0);
151 + }
152 + }
153 +
154 + if(freq > 0) update_every = freq;
155 +}
156 +
157 +int main(int argc, char **argv)
158 +{
159 + // debug_flags = D_PROCFILE;
160 + stderror = stderr;
161 +
162 + // set the name for logging
163 + program_name = "debugfs.plugin";
164 +
165 + // disable syslog for debugfs.plugin
166 + error_log_syslog = 0;
167 +
168 + netdata_configured_host_prefix = getenv("NETDATA_HOST_PREFIX");
169 + if (verify_netdata_host_prefix() == -1)
170 + exit(1);
171 +
172 + user_config_dir = getenv("NETDATA_USER_CONFIG_DIR");
173 + if (user_config_dir == NULL) {
174 + user_config_dir = CONFIG_DIR;
175 + }
176 +
177 + stock_config_dir = getenv("NETDATA_STOCK_CONFIG_DIR");
178 + if (stock_config_dir == NULL) {
179 + // info("NETDATA_CONFIG_DIR is not passed from netdata");
180 + stock_config_dir = LIBCONFIG_DIR;
181 + }
182 +
183 + // FIXME: should first check if /sys/kernel/debug is mounted
184 +
185 + // FIXME: remove debugfs_check_sys_permission() after https://github.com/netdata/netdata/issues/15048 is fixed
186 + if (!debugfs_check_capabilities() && !debugfs_am_i_running_as_root() && !debugfs_check_sys_permission()) {
187 + uid_t uid = getuid(), euid = geteuid();
188 +#ifdef HAVE_CAPABILITY
189 + error(
190 + "debugfs.plugin should either run as root (now running with uid %u, euid %u) or have special capabilities. "
191 + "Without these, debugfs.plugin cannot access /sys/kernel/debug. "
192 + "To enable capabilities run: sudo setcap cap_dac_read_search,cap_sys_ptrace+ep %s; "
193 + "To enable setuid to root run: sudo chown root:netdata %s; sudo chmod 4750 %s; ",
194 + uid,
195 + euid,
196 + argv[0],
197 + argv[0],
198 + argv[0]);
199 +#else
200 + error(
201 + "debugfs.plugin should either run as root (now running with uid %u, euid %u) or have special capabilities. "
202 + "Without these, debugfs.plugin cannot access /sys/kernel/debug."
203 + "Your system does not support capabilities. "
204 + "To enable setuid to root run: sudo chown root:netdata %s; sudo chmod 4750 %s; ",
205 + uid,
206 + euid,
207 + argv[0],
208 + argv[0]);
209 +#endif
210 + exit(1);
211 + }
212 +
213 + // if (!debugfs_check_sys_permission()) {
214 + // exit(2);
215 + // }
216 +
217 + debugfs_parse_args(argc, argv);
218 +
219 + size_t iteration;
220 + usec_t step = update_every * USEC_PER_SEC;
221 + heartbeat_t hb;
222 + heartbeat_init(&hb);
223 +
224 + for (iteration = 0; iteration < 86400; iteration++) {
225 + heartbeat_next(&hb, step);
226 + int enabled = 0;
227 +
228 + for (int i = 0; debugfs_modules[i].name; i++) {
229 + struct debugfs_module *pm = &debugfs_modules[i];
230 + if (unlikely(!pm->enabled))
231 + continue;
232 +
233 + pm->enabled = !pm->func(update_every, pm->name);
234 + if (likely(pm->enabled))
235 + enabled++;
236 + }
237 + if (!enabled) {
238 + info("all modules are disabled, exiting...");
239 + return 1;
240 + }
241 + }
242 +
243 + return 0;
244 +}
collectors/debugfs.plugin/debugfs_plugin.h new
+16
@@ -0,0 +1,16 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_DEBUGFS_PLUGIN_H
4 +#define NETDATA_DEBUGFS_PLUGIN_H 1
5 +
6 +#include "libnetdata/libnetdata.h"
7 +#include "collectors/all.h"
8 +#include "database/rrd.h"
9 +
10 +int do_debugfs_extfrag(int update_every, const char *name);
11 +int do_debugfs_zswap(int update_every, const char *name);
12 +void debugfs2lower(char *name);
13 +const char *debugfs_rrdset_type_name(RRDSET_TYPE chart_type);
14 +const char *debugfs_rrd_algorithm_name(RRD_ALGORITHM algorithm);
15 +
16 +#endif // NETDATA_DEBUGFS_PLUGIN_H
collectors/debugfs.plugin/debugfs_zswap.c new
+432
@@ -0,0 +1,432 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "debugfs_plugin.h"
4 +
5 +static long system_page_size = 4096;
6 +
7 +static collected_number pages_to_bytes(collected_number value)
8 +{
9 + return value * system_page_size;
10 +}
11 +
12 +struct netdata_zswap_metric {
13 + const char *filename;
14 +
15 + const char *chart_id;
16 + const char *title;
17 + const char *units;
18 + RRDSET_TYPE charttype;
19 + int prio;
20 + const char *dimension;
21 + RRD_ALGORITHM algorithm;
22 + int divisor;
23 +
24 + int enabled;
25 + int chart_created;
26 +
27 + collected_number value;
28 + collected_number (*convertv)(collected_number v);
29 +};
30 +
31 +static struct netdata_zswap_metric zswap_calculated_metrics[] = {
32 + {.filename = "",
33 + .chart_id = "pool_compression_ratio",
34 + .dimension = "compression_ratio",
35 + .units = "ratio",
36 + .title = "Zswap compression ratio",
37 + .algorithm = RRD_ALGORITHM_ABSOLUTE,
38 + .charttype = RRDSET_TYPE_LINE,
39 + .enabled = CONFIG_BOOLEAN_YES,
40 + .chart_created = CONFIG_BOOLEAN_NO,
41 + .prio = NETDATA_CHART_PRIO_SYSTEM_ZSWAP_COMPRESS_RATIO,
42 + .divisor = 100,
43 + .convertv = NULL,
44 + .value = -1},
45 +};
46 +
47 +enum netdata_zswap_calculated {
48 + NETDATA_ZSWAP_COMPRESSION_RATIO_CHART,
49 +};
50 +
51 +enum netdata_zwap_independent {
52 + NETDATA_ZSWAP_POOL_TOTAL_SIZE,
53 + NETDATA_ZSWAP_STORED_PAGES,
54 + NETDATA_ZSWAP_POOL_LIMIT_HIT,
55 + NETDATA_ZSWAP_WRITTEN_BACK_PAGES,
56 + NETDATA_ZSWAP_SAME_FILLED_PAGES,
57 + NETDATA_ZSWAP_DUPLICATE_ENTRY,
58 +
59 + // Terminator
60 + NETDATA_ZSWAP_SITE_END
61 +};
62 +
63 +static struct netdata_zswap_metric zswap_independent_metrics[] = {
64 + // https://elixir.bootlin.com/linux/latest/source/mm/zswap.c
65 + {.filename = "/sys/kernel/debug/zswap/pool_total_size",
66 + .chart_id = "pool_compressed_size",
67 + .dimension = "compressed_size",
68 + .units = "bytes",
69 + .title = "Zswap compressed bytes currently stored",
70 + .algorithm = RRD_ALGORITHM_ABSOLUTE,
71 + .charttype = RRDSET_TYPE_AREA,
72 + .enabled = CONFIG_BOOLEAN_YES,
73 + .chart_created = CONFIG_BOOLEAN_NO,
74 + .prio = NETDATA_CHART_PRIO_SYSTEM_ZSWAP_POOL_TOT_SIZE,
75 + .divisor = 1,
76 + .convertv = NULL,
77 + .value = -1},
78 + {.filename = "/sys/kernel/debug/zswap/stored_pages",
79 + .chart_id = "pool_raw_size",
80 + .dimension = "uncompressed_size",
81 + .units = "bytes",
82 + .title = "Zswap uncompressed bytes currently stored",
83 + .algorithm = RRD_ALGORITHM_ABSOLUTE,
84 + .charttype = RRDSET_TYPE_AREA,
85 + .enabled = CONFIG_BOOLEAN_YES,
86 + .chart_created = CONFIG_BOOLEAN_NO,
87 + .prio = NETDATA_CHART_PRIO_SYSTEM_ZSWAP_STORED_PAGE,
88 + .divisor = 1,
89 + .convertv = pages_to_bytes,
90 + .value = -1},
91 + {.filename = "/sys/kernel/debug/zswap/pool_limit_hit",
92 + .chart_id = "pool_limit_hit",
93 + .dimension = "limit",
94 + .units = "events/s",
95 + .title = "Zswap pool limit was reached",
96 + .algorithm = RRD_ALGORITHM_INCREMENTAL,
97 + .charttype = RRDSET_TYPE_LINE,
98 + .enabled = CONFIG_BOOLEAN_YES,
99 + .chart_created = CONFIG_BOOLEAN_NO,
100 + .prio = NETDATA_CHART_PRIO_SYSTEM_ZSWAP_POOL_LIM_HIT,
101 + .divisor = 1,
102 + .convertv = NULL,
103 + .value = -1},
104 + {.filename = "/sys/kernel/debug/zswap/written_back_pages",
105 + .chart_id = "written_back_raw_bytes",
106 + .dimension = "written_back",
107 + .units = "bytes/s",
108 + .title = "Zswap uncomressed bytes written back when pool limit was reached",
109 + .algorithm = RRD_ALGORITHM_INCREMENTAL,
110 + .charttype = RRDSET_TYPE_AREA,
111 + .enabled = CONFIG_BOOLEAN_YES,
112 + .chart_created = CONFIG_BOOLEAN_NO,
113 + .prio = NETDATA_CHART_PRIO_SYSTEM_ZSWAP_WRT_BACK_PAGES,
114 + .divisor = 1,
115 + .convertv = pages_to_bytes,
116 + .value = -1},
117 + {.filename = "/sys/kernel/debug/zswap/same_filled_pages",
118 + .chart_id = "same_filled_raw_size",
119 + .dimension = "same_filled",
120 + .units = "bytes",
121 + .title = "Zswap same-value filled uncompressed bytes currently stored",
122 + .algorithm = RRD_ALGORITHM_ABSOLUTE,
123 + .charttype = RRDSET_TYPE_AREA,
124 + .enabled = CONFIG_BOOLEAN_YES,
125 + .chart_created = CONFIG_BOOLEAN_NO,
126 + .prio = NETDATA_CHART_PRIO_SYSTEM_ZSWAP_SAME_FILL_PAGE,
127 + .divisor = 1,
128 + .convertv = pages_to_bytes,
129 + .value = -1},
130 + {.filename = "/sys/kernel/debug/zswap/duplicate_entry",
131 + .chart_id = "duplicate_entry",
132 + .dimension = "duplicate",
133 + .units = "entries/s",
134 + .title = "Zswap duplicate store was encountered",
135 + .algorithm = RRD_ALGORITHM_INCREMENTAL,
136 + .charttype = RRDSET_TYPE_LINE,
137 + .enabled = CONFIG_BOOLEAN_YES,
138 + .chart_created = CONFIG_BOOLEAN_NO,
139 + .prio = NETDATA_CHART_PRIO_SYSTEM_ZSWAP_DUPP_ENTRY,
140 + .divisor = 1,
141 + .convertv = NULL,
142 + .value = -1},
143 +
144 + // The terminator
145 + {.filename = NULL,
146 + .chart_id = NULL,
147 + .dimension = NULL,
148 + .units = NULL,
149 + .title = NULL,
150 + .algorithm = RRD_ALGORITHM_ABSOLUTE,
151 + .charttype = RRDSET_TYPE_LINE,
152 + .enabled = CONFIG_BOOLEAN_NO,
153 + .chart_created = CONFIG_BOOLEAN_NO,
154 + .prio = -1,
155 + .value = -1}};
156 +
157 +enum netdata_zswap_rejected {
158 + NETDATA_ZSWAP_REJECTED_CHART,
159 + NETDATA_ZSWAP_REJECTED_COMPRESS_POOR,
160 + NETDATA_ZSWAP_REJECTED_KMEM_FAIL,
161 + NETDATA_ZSWAP_REJECTED_RALLOC_FAIL,
162 + NETDATA_ZSWAP_REJECTED_RRECLAIM_FAIL,
163 +
164 + // Terminator
165 + NETDATA_ZSWAP_REJECTED_END
166 +};
167 +
168 +static struct netdata_zswap_metric zswap_rejected_metrics[] = {
169 + {.filename = "/sys/kernel/debug/zswap/",
170 + .chart_id = "rejections",
171 + .dimension = NULL,
172 + .units = "rejections/s",
173 + .title = "Zswap rejections",
174 + .algorithm = RRD_ALGORITHM_INCREMENTAL,
175 + .charttype = RRDSET_TYPE_STACKED,
176 + .enabled = CONFIG_BOOLEAN_YES,
177 + .chart_created = CONFIG_BOOLEAN_NO,
178 + .prio = NETDATA_CHART_PRIO_SYSTEM_ZSWAP_REJECTS,
179 + .divisor = 1,
180 + .convertv = NULL,
181 + .value = -1},
182 + {.filename = "/sys/kernel/debug/zswap/reject_compress_poor",
183 + .chart_id = "reject_compress_poor",
184 + .dimension = "compress_poor",
185 + .units = NULL,
186 + .title = NULL,
187 + .algorithm = RRD_ALGORITHM_INCREMENTAL,
188 + .charttype = RRDSET_TYPE_STACKED,
189 + .enabled = CONFIG_BOOLEAN_YES,
190 + .chart_created = CONFIG_BOOLEAN_NO,
191 + .prio = NETDATA_CHART_PRIO_SYSTEM_ZSWAP_REJECTS,
192 + .divisor = 1,
193 + .convertv = NULL,
194 + .value = -1},
195 + {.filename = "/sys/kernel/debug/zswap/reject_kmemcache_fail",
196 + .chart_id = "reject_kmemcache_fail",
197 + .dimension = "kmemcache_fail",
198 + .units = NULL,
199 + .title = NULL,
200 + .algorithm = RRD_ALGORITHM_INCREMENTAL,
201 + .charttype = RRDSET_TYPE_STACKED,
202 + .enabled = CONFIG_BOOLEAN_YES,
203 + .chart_created = CONFIG_BOOLEAN_NO,
204 + .prio = NETDATA_CHART_PRIO_SYSTEM_ZSWAP_REJECTS,
205 + .divisor = 1,
206 + .convertv = NULL,
207 + .value = -1},
208 + {.filename = "/sys/kernel/debug/zswap/reject_alloc_fail",
209 + .chart_id = "reject_alloc_fail",
210 + .dimension = "alloc_fail",
211 + .units = NULL,
212 + .title = NULL,
213 + .algorithm = RRD_ALGORITHM_INCREMENTAL,
214 + .charttype = RRDSET_TYPE_STACKED,
215 + .enabled = CONFIG_BOOLEAN_YES,
216 + .chart_created = CONFIG_BOOLEAN_NO,
217 + .prio = NETDATA_CHART_PRIO_SYSTEM_ZSWAP_REJECTS,
218 + .divisor = 1,
219 + .convertv = NULL,
220 + .value = -1},
221 + {.filename = "/sys/kernel/debug/zswap/reject_reclaim_fail",
222 + .chart_id = "reject_reclaim_fail",
223 + .dimension = "reclaim_fail",
224 + .units = NULL,
225 + .title = NULL,
226 + .algorithm = RRD_ALGORITHM_INCREMENTAL,
227 + .charttype = RRDSET_TYPE_STACKED,
228 + .enabled = CONFIG_BOOLEAN_YES,
229 + .chart_created = CONFIG_BOOLEAN_NO,
230 + .prio = NETDATA_CHART_PRIO_SYSTEM_ZSWAP_REJECTS,
231 + .divisor = 1,
232 + .convertv = NULL,
233 + .value = -1},
234 +
235 + // The terminator
236 + {.filename = NULL,
237 + .chart_id = NULL,
238 + .dimension = NULL,
239 + .units = NULL,
240 + .title = NULL,
241 + .algorithm = RRD_ALGORITHM_ABSOLUTE,
242 + .charttype = RRDSET_TYPE_STACKED,
243 + .enabled = CONFIG_BOOLEAN_NO,
244 + .chart_created = CONFIG_BOOLEAN_NO,
245 + .prio = -1,
246 + .value = -1}};
247 +
248 +int zswap_collect_data(struct netdata_zswap_metric *metric)
249 +{
250 + int fd;
251 + int ret = 0;
252 + char buffer[512];
253 +
254 + char filename[FILENAME_MAX + 1];
255 + snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, metric->filename);
256 + // we are not using profile_open/procfile_read, because they will generate error during runtime.
257 + fd = open(filename, O_RDONLY, 0444);
258 + if (fd < 0) {
259 + error("Cannot open file %s", filename);
260 + return -1;
261 + }
262 +
263 + ssize_t r = read(fd, buffer, 511);
264 + // We expect at list 1 character
265 + if (r < 2) {
266 + error("Cannot parse file %s", filename);
267 + ret = -1;
268 + goto zswap_collect_end;
269 + }
270 +
271 + // We discard breakline
272 + buffer[r - 1] = '\0';
273 + metric->value = str2ll(buffer, NULL);
274 +
275 + if (metric->convertv)
276 + metric->value = metric->convertv(metric->value);
277 +
278 +zswap_collect_end:
279 + close(fd);
280 + return ret;
281 +}
282 +
283 +static void
284 +zswap_send_chart(struct netdata_zswap_metric *metric, int update_every, const char *name, const char *option)
285 +{
286 + fprintf(
287 + stdout,
288 + "CHART system.zswap_%s '' '%s' '%s' 'zswap' '' '%s' %d %d '%s' 'debugfs.plugin' '%s'\n",
289 + metric->chart_id,
290 + metric->title,
291 + metric->units,
292 + debugfs_rrdset_type_name(metric->charttype),
293 + metric->prio,
294 + update_every,
295 + (!option) ? "" : option,
296 + name);
297 +}
298 +
299 +static void zswap_send_dimension(struct netdata_zswap_metric *metric)
300 +{
301 + int div = metric->divisor > 0 ? metric->divisor : 1;
302 + fprintf(
303 + stdout,
304 + "DIMENSION '%s' '%s' %s 1 %d ''\n",
305 + metric->dimension,
306 + metric->dimension,
307 + debugfs_rrd_algorithm_name(metric->algorithm),
308 + div);
309 +}
310 +
311 +static void zswap_send_begin(struct netdata_zswap_metric *metric)
312 +{
313 + fprintf(stdout, "BEGIN system.zswap_%s\n", metric->chart_id);
314 +}
315 +
316 +static void zswap_send_set(struct netdata_zswap_metric *metric)
317 +{
318 + fprintf(stdout, "SET %s = %lld\n", metric->dimension, metric->value);
319 +}
320 +
321 +static void zswap_send_end_and_flush()
322 +{
323 + fprintf(stdout, "END\n");
324 + fflush(stdout);
325 +}
326 +
327 +static void zswap_independent_chart(struct netdata_zswap_metric *metric, int update_every, const char *name)
328 +{
329 + if (unlikely(!metric->chart_created)) {
330 + metric->chart_created = CONFIG_BOOLEAN_YES;
331 +
332 + zswap_send_chart(metric, update_every, name, NULL);
333 + zswap_send_dimension(metric);
334 + }
335 +
336 + zswap_send_begin(metric);
337 + zswap_send_set(metric);
338 + zswap_send_end_and_flush();
339 +}
340 +
341 +void zswap_reject_chart(int update_every, const char *name)
342 +{
343 + struct netdata_zswap_metric *metric = &zswap_rejected_metrics[NETDATA_ZSWAP_REJECTED_CHART];
344 +
345 + if (unlikely(!metric->chart_created)) {
346 + metric->chart_created = CONFIG_BOOLEAN_YES;
347 +
348 + zswap_send_chart(metric, update_every, name, NULL);
349 + for (int i = NETDATA_ZSWAP_REJECTED_COMPRESS_POOR; zswap_rejected_metrics[i].filename; i++) {
350 + metric = &zswap_rejected_metrics[i];
351 + if (likely(metric->enabled))
352 + zswap_send_dimension(metric);
353 + }
354 + }
355 +
356 + metric = &zswap_rejected_metrics[NETDATA_ZSWAP_REJECTED_CHART];
357 + zswap_send_begin(metric);
358 + for (int i = NETDATA_ZSWAP_REJECTED_COMPRESS_POOR; zswap_rejected_metrics[i].filename; i++) {
359 + metric = &zswap_rejected_metrics[i];
360 + if (likely(metric->enabled))
361 + zswap_send_set(metric);
362 + }
363 + zswap_send_end_and_flush();
364 +}
365 +
366 +static void zswap_obsolete_charts(int update_every, const char *name)
367 +{
368 + struct netdata_zswap_metric *metric = NULL;
369 +
370 + for (int i = 0; zswap_independent_metrics[i].filename; i++) {
371 + metric = &zswap_independent_metrics[i];
372 + if (likely(metric->chart_created))
373 + zswap_send_chart(metric, update_every, name, "obsolete");
374 + }
375 +
376 + metric = &zswap_rejected_metrics[NETDATA_ZSWAP_REJECTED_CHART];
377 + if (likely(metric->chart_created))
378 + zswap_send_chart(metric, update_every, name, "obsolete");
379 +
380 + metric = &zswap_calculated_metrics[NETDATA_ZSWAP_COMPRESSION_RATIO_CHART];
381 + if (likely(metric->chart_created))
382 + zswap_send_chart(metric, update_every, name, "obsolete");
383 +}
384 +
385 +int do_debugfs_zswap(int update_every, const char *name)
386 +{
387 + system_page_size = sysconf(_SC_PAGESIZE);
388 + struct netdata_zswap_metric *metric = NULL;
389 + int enabled = 0;
390 +
391 + for (int i = 0; zswap_independent_metrics[i].filename; i++) {
392 + metric = &zswap_independent_metrics[i];
393 + if (unlikely(!metric->enabled))
394 + continue;
395 + if (unlikely(!(metric->enabled = !zswap_collect_data(metric))))
396 + continue;
397 + zswap_independent_chart(metric, update_every, name);
398 + enabled++;
399 + }
400 +
401 + struct netdata_zswap_metric *metric_size = &zswap_independent_metrics[NETDATA_ZSWAP_POOL_TOTAL_SIZE];
402 + struct netdata_zswap_metric *metric_raw_size = &zswap_independent_metrics[NETDATA_ZSWAP_STORED_PAGES];
403 + if (metric_size->enabled && metric_raw_size->enabled) {
404 + metric = &zswap_calculated_metrics[NETDATA_ZSWAP_COMPRESSION_RATIO_CHART];
405 + metric->value = 0;
406 + if (metric_size->value > 0)
407 + metric->value =
408 + (collected_number)((NETDATA_DOUBLE)metric_raw_size->value / (NETDATA_DOUBLE)metric_size->value * 100);
409 + zswap_independent_chart(metric, update_every, name);
410 + }
411 +
412 + int enabled_rejected = 0;
413 + for (int i = NETDATA_ZSWAP_REJECTED_COMPRESS_POOR; zswap_rejected_metrics[i].filename; i++) {
414 + metric = &zswap_rejected_metrics[i];
415 + if (unlikely(!metric->enabled))
416 + continue;
417 + if (unlikely(!(metric->enabled = !zswap_collect_data(metric))))
418 + continue;
419 + enabled++;
420 + enabled_rejected++;
421 + }
422 +
423 + if (likely(enabled_rejected > 0))
424 + zswap_reject_chart(update_every, name);
425 +
426 + if (!enabled) {
427 + zswap_obsolete_charts(update_every, name);
428 + return -1;
429 + }
430 +
431 + return 0;
432 +}
collectors/debugfs.plugin/metrics.csv new
+12
@@ -0,0 +1,12 @@
1 +metric,scode,dimensions,unit,description,chart_type,labels,plugin,module
2 +mem.fragmentation_index_dma,node,"order0, order1, order2, order3, order4, order5, order6, order7, order8, order9, order10",index,Memory fragmentation index for each order,line,numa_node,debugfs.plugin,/sys/kernel/debug/extfrag
3 +mem.fragmentation_index_dma32,node,"order0, order1, order2, order3, order4, order5, order6, order7, order8, order9, order10",index,Memory fragmentation index for each order,line,numa_node,debugfs.plugin,/sys/kernel/debug/extfrag
4 +mem.fragmentation_index_normal,node,"order0, order1, order2, order3, order4, order5, order6, order7, order8, order9, order10",index,Memory fragmentation index for each order,line,numa_node,debugfs.plugin,/sys/kernel/debug/extfrag
5 +system.zswap_pool_compression_ratio,,compression_ratio,ratio,Zswap compression ratio,line,,debugfs.plugin,/sys/kernel/debug/zswap
6 +system.zswap_pool_compressed_size,,compressed_size,bytes,Zswap compressed bytes currently stored,area,,debugfs.plugin,/sys/kernel/debug/zswap
7 +system.zswap_pool_raw_size,,uncompressed_size,bytes,Zswap uncompressed bytes currently stored,area,,debugfs.plugin,/sys/kernel/debug/zswap
8 +system.zswap_rejections,,"compress_poor, kmemcache_fail, alloc_fail, reclaim_fail",rejections/s,Zswap rejections,stacked,,debugfs.plugin,/sys/kernel/debug/zswap
9 +system.zswap_pool_limit_hit,,limit,events/s,Zswap pool limit was reached,line,,debugfs.plugin,/sys/kernel/debug/zswap
10 +system.zswap_written_back_raw_bytes,,written_back,bytes/s,Zswap uncomressed bytes written back when pool limit was reached,area,,debugfs.plugin,/sys/kernel/debug/zswap
11 +system.zswap_same_filled_raw_size,,same_filled,bytes,Zswap same-value filled uncompressed bytes currently stored,area,,debugfs.plugin,/sys/kernel/debug/zswap
12 +system.zswap_duplicate_entry,,duplicate,entries/s,Zswap duplicate store was encountered,line,,debugfs.plugin,/sys/kernel/debug/zswap
collectors/ebpf.plugin/ebpf_swap.c
+1 -1
@@ -752,7 +752,7 @@ static void ebpf_create_swap_charts(int update_every)
752 EBPF_COMMON_DIMENSION_CALL, NETDATA_SYSTEM_SWAP_SUBMENU,
753 NULL,
754 NETDATA_EBPF_CHART_TYPE_LINE,
755 - 202,
755 + NETDATA_CHART_PRIO_SYSTEM_SWAP_CALLS,
756 ebpf_create_global_dimension,
757 swap_publish_aggregated, NETDATA_SWAP_END,
758 update_every, NETDATA_EBPF_MODULE_NAME_SWAP);
configure.ac
+16
@@ -1293,6 +1293,21 @@ if test "${build_ml}" = "yes"; then
1293 fi
1294
1295
1296 +# -----------------------------------------------------------------------------
1297 +# debugfs.plugin
1298 +
1299 +if test "${build_target}" = "linux"; then
1300 + AC_DEFINE([ENABLE_DEBUGFS_PLUGIN], [1], [debugfs.plugin])
1301 + enable_plugin_debugfs="yes"
1302 +else
1303 + enable_plugin_debugfs="no"
1304 +fi
1305 +
1306 +AC_MSG_CHECKING([if debugfs.plugin should be enabled])
1307 +AC_MSG_RESULT([${enable_plugin_debugfs}])
1308 +AM_CONDITIONAL([ENABLE_PLUGIN_DEBUGFS], [test "${enable_plugin_debugfs}" = "yes"])
1309 +
1310 +
1311 # -----------------------------------------------------------------------------
1312 # ebpf.plugin
1313
@@ -1808,6 +1823,7 @@ AC_CONFIG_FILES([
1823 collectors/apps.plugin/Makefile
1824 collectors/cgroups.plugin/Makefile
1825 collectors/charts.d.plugin/Makefile
1826 + collectors/debugfs.plugin/Makefile
1827 collectors/diskspace.plugin/Makefile
1828 collectors/timex.plugin/Makefile
1829 collectors/ioping.plugin/Makefile
contrib/debian/netdata.postinst
+1
@@ -61,6 +61,7 @@ case "$1" in
61 chown -R root:netdata /usr/libexec/netdata/plugins.d
62 setcap cap_dac_read_search,cap_sys_ptrace+ep /usr/libexec/netdata/plugins.d/apps.plugin
63 setcap cap_dac_read_search+ep /usr/libexec/netdata/plugins.d/slabinfo.plugin
64 + setcap cap_dac_read_search+ep /usr/libexec/netdata/plugins.d/debugfs.plugin
65
66 if capsh --supports=cap_perfmon 2>/dev/null; then
67 setcap cap_perfmon+ep /usr/libexec/netdata/plugins.d/perf.plugin
contrib/debian/rules
+1
@@ -113,6 +113,7 @@ override_dh_fixperms:
113 # given extra capabilities in the postinst script.
114 #
115 chmod 0750 $(TOP)/usr/libexec/netdata/plugins.d/apps.plugin
116 + chmod 0750 $(TOP)/usr/libexec/netdata/plugins.d/debugfs.plugin
117 chmod 0750 $(TOP)/usr/libexec/netdata/plugins.d/perf.plugin
118 chmod 0750 $(TOP)/usr/libexec/netdata/plugins.d/slabinfo.plugin
119 chmod 0750 $(TOP)/usr/libexec/netdata/plugins.d/go.d.plugin
daemon/buildinfo.c
+11
@@ -115,6 +115,12 @@
115 #define FEAT_APPS_PLUGIN 0
116 #endif
117
118 +#ifdef ENABLE_DEBUGFS_PLUGIN
119 +#define FEAT_DEBUGFS_PLUGIN 1
120 +#else
121 +#define FEAT_DEBUGFS_PLUGIN 0
122 +#endif
123 +
124 #ifdef HAVE_FREEIPMI
125 #define FEAT_IPMI 1
126 #else
@@ -291,6 +297,7 @@ void print_build_info(void) {
297 printf(" apps: %s\n", FEAT_YES_NO(FEAT_APPS_PLUGIN));
298 printf(" cgroup Network Tracking: %s\n", FEAT_YES_NO(FEAT_CGROUP_NET));
299 printf(" CUPS: %s\n", FEAT_YES_NO(FEAT_CUPS));
300 + printf(" debugfs: %s\n", FEAT_YES_NO(FEAT_DEBUGFS_PLUGIN));
301 printf(" EBPF: %s\n", FEAT_YES_NO(FEAT_EBPF));
302 printf(" IPMI: %s\n", FEAT_YES_NO(FEAT_IPMI));
303 printf(" NFACCT: %s\n", FEAT_YES_NO(FEAT_NFACCT));
@@ -349,6 +356,7 @@ void print_build_info_json(void) {
356 printf(" \"apps\": %s,\n", FEAT_JSON_BOOL(FEAT_APPS_PLUGIN));
357 printf(" \"cgroup-net\": %s,\n", FEAT_JSON_BOOL(FEAT_CGROUP_NET));
358 printf(" \"cups\": %s,\n", FEAT_JSON_BOOL(FEAT_CUPS));
359 + printf(" \"debugfs\": %s,\n", FEAT_JSON_BOOL(FEAT_DEBUGFS_PLUGIN));
360 printf(" \"ebpf\": %s,\n", FEAT_JSON_BOOL(FEAT_EBPF));
361 printf(" \"ipmi\": %s,\n", FEAT_JSON_BOOL(FEAT_IPMI));
362 printf(" \"nfacct\": %s,\n", FEAT_JSON_BOOL(FEAT_NFACCT));
@@ -424,6 +432,9 @@ void analytics_build_info(BUFFER *b) {
432 #ifdef ENABLE_APPS_PLUGIN
433 add_to_bi(b, "apps");
434 #endif
435 +#ifdef ENABLE_DEBUGFS_PLUGIN
436 + add_to_bi(b, "debugfs");
437 +#endif
438 #ifdef HAVE_SETNS
439 add_to_bi(b, "cgroup Network Tracking");
440 #endif
netdata-installer.sh
+17
@@ -1229,6 +1229,23 @@ if [ "$(id -u)" -eq 0 ]; then
1229 fi
1230 fi
1231
1232 + if [ -f "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/debugfs.plugin" ]; then
1233 + run chown "root:${NETDATA_GROUP}" "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/debugfs.plugin"
1234 + capabilities=0
1235 + if ! iscontainer && command -v setcap 1> /dev/null 2>&1; then
1236 + run chmod 0750 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/debugfs.plugin"
1237 + if run setcap cap_dac_read_search+ep "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/debugfs.plugin"; then
1238 + # if we managed to setcap, but we fail to execute debugfs.plugin setuid to root
1239 + "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/debugfs.plugin" -t > /dev/null 2>&1 && capabilities=1 || capabilities=0
1240 + fi
1241 + fi
1242 +
1243 + if [ $capabilities -eq 0 ]; then
1244 + # fix debugfs.plugin to be setuid to root
1245 + run chmod 4750 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/debugfs.plugin"
1246 + fi
1247 + fi
1248 +
1249 if [ -f "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/freeipmi.plugin" ]; then
1250 run chown "root:${NETDATA_GROUP}" "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/freeipmi.plugin"
1251 run chmod 4750 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/freeipmi.plugin"
netdata.spec.in
+8 -1
@@ -280,6 +280,10 @@ install -m 4750 -p freeipmi.plugin "${RPM_BUILD_ROOT}%{_libexecdir}/%{name}/plug
280 # Install apps.plugin
281 install -m 4750 -p apps.plugin "${RPM_BUILD_ROOT}%{_libexecdir}/%{name}/plugins.d/apps.plugin"
282
283 +# ###########################################################
284 +# Install debugfs.plugin
285 +install -m 0750 -p debugfs.plugin "${RPM_BUILD_ROOT}%{_libexecdir}/%{name}/plugins.d/debugfs.plugin"
286 +
287 # ###########################################################
288 # Install perf.plugin
289 install -m 4750 -p perf.plugin "${RPM_BUILD_ROOT}%{_libexecdir}/%{name}/plugins.d/perf.plugin"
@@ -501,7 +505,10 @@ rm -rf "${RPM_BUILD_ROOT}"
505 # %caps(cap_perfmon=ep) %attr(0750,root,netdata) %{_libexecdir}/%{name}/plugins.d/perf.plugin
506 %caps(cap_sys_admin=ep) %attr(0750,root,netdata) %{_libexecdir}/%{name}/plugins.d/perf.plugin
507
504 -# perf plugin
508 +# debugfs plugin
509 +%caps(cap_dac_read_search=ep) %attr(0750,root,netdata) %{_libexecdir}/%{name}/plugins.d/debugfs.plugin
510 +
511 +# slabinfo plugin
512 %caps(cap_dac_read_search=ep) %attr(0750,root,netdata) %{_libexecdir}/%{name}/plugins.d/slabinfo.plugin
513
514 # go.d.plugin (the capability required for wireguard module)
packaging/docker/Dockerfile
+2 -1
@@ -104,7 +104,8 @@ RUN chown -R root:root \
104 chmod 0755 /usr/libexec/netdata/plugins.d/*.plugin && \
105 chmod 4755 \
106 /usr/libexec/netdata/plugins.d/cgroup-network \
107 - /usr/libexec/netdata/plugins.d/apps.plugin && \
107 + /usr/libexec/netdata/plugins.d/apps.plugin \
108 + /usr/libexec/netdata/plugins.d/debugfs.plugin && \
109 if [ -f /usr/libexec/netdata/plugins.d/freeipmi.plugin ]; then \
110 chmod 4755 /usr/libexec/netdata/plugins.d/freeipmi.plugin; \
111 fi && \
packaging/makeself/install-or-update.sh
+2 -1
@@ -171,6 +171,7 @@ progress "changing plugins ownership and permissions"
171 if command -v setcap >/dev/null 2>&1; then
172 run setcap "cap_dac_read_search,cap_sys_ptrace=ep" "usr/libexec/netdata/plugins.d/apps.plugin"
173 run setcap "cap_dac_read_search=ep" "usr/libexec/netdata/plugins.d/slabinfo.plugin"
174 + run setcap "cap_dac_read_search=ep" "usr/libexec/netdata/plugins.d/debugfs.plugin"
175
176 if command -v capsh >/dev/null 2>&1 && capsh --supports=cap_perfmon 2>/dev/null ; then
177 run setcap "cap_perfmon=ep" "usr/libexec/netdata/plugins.d/perf.plugin"
@@ -180,7 +181,7 @@ if command -v setcap >/dev/null 2>&1; then
181
182 run setcap "cap_net_admin,cap_net_raw=eip" "usr/libexec/netdata/plugins.d/go.d.plugin"
183 else
183 - for x in apps.plugin perf.plugin slabinfo.plugin; do
184 + for x in apps.plugin perf.plugin slabinfo.plugin debugfs.plugin; do
185 f="usr/libexec/netdata/plugins.d/${x}"
186 run chown root:${NETDATA_GROUP} "${f}"
187 run chmod 4750 "${f}"
web/gui/dashboard_info.js
+21
@@ -883,6 +883,19 @@ netdataDashboard.submenu = {
883 'When the kernel or an application requests some memory, the buddy allocator provides a page that matches closest the request.'
884 },
885
886 + 'mem.fragmentation': {
887 + info: 'These charts show whether the kernel will compact memory or direct reclaim to satisfy a high-order allocation. '+
888 + 'The extfrag/extfrag_index file in debugfs shows what the fragmentation index for each order is in each zone in the system.' +
889 + 'Values tending towards 0 imply allocations would fail due to lack of memory, values towards 1000 imply failures are due to ' +
890 + 'fragmentation and -1 implies that the allocation will succeed as long as watermarks are met.'
891 + },
892 +
893 + 'system.zswap': {
894 + info : 'Zswap is a backend for frontswap that takes pages that are in the process of being swapped out and attempts to compress and store them in a ' +
895 + 'RAM-based memory pool. This can result in a significant I/O reduction on the swap device and, in the case where decompressing from RAM is faster ' +
896 + 'than reading from the swap device, can also improve workload performance.'
897 + },
898 +
899 'ip.ecn': {
900 info: '<a href="https://en.wikipedia.org/wiki/Explicit_Congestion_Notification" target="_blank">Explicit Congestion Notification (ECN)</a> '+
901 'is an extension to the IP and to the TCP that allows end-to-end notification of network congestion without dropping packets. '+
@@ -1522,6 +1535,14 @@ netdataDashboard.context = {
1535 info: '<a href="https://en.wikipedia.org/wiki/Entropy_(computing)" target="_blank">Entropy</a>, is a pool of random numbers (<a href="https://en.wikipedia.org/wiki//dev/random" target="_blank">/dev/random</a>) that is mainly used in cryptography. If the pool of entropy gets empty, processes requiring random numbers may run a lot slower (it depends on the interface each program uses), waiting for the pool to be replenished. Ideally a system with high entropy demands should have a hardware device for that purpose (TPM is one such device). There are also several software-only options you may install, like <code>haveged</code>, although these are generally useful only in servers.'
1536 },
1537
1538 + 'system.zswap_rejections': {
1539 + info: '<p>Zswap rejected pages per access.</p>' +
1540 + '<p><b>CompressPoor</b> - compressed page was too big for the allocator to store. ' +
1541 + '<b>KmemcacheFail</b> - number of entry metadata that could not be allocated. ' +
1542 + '<b>AllocFail</b> - allocator could not get memory. ' +
1543 + '<b>ReclaimFail</b> - memory cannot be reclaimed (pool limit was reached).</p>'
1544 + },
1545 +
1546 'system.clock_sync_state': {
1547 info:'<p>The system clock synchronization state as provided by the <a href="https://man7.org/linux/man-pages/man2/adjtimex.2.html" target="_blank">ntp_adjtime()</a> system call. '+
1548 'An unsynchronized clock may be the result of synchronization issues by the NTP daemon or a hardware clock fault. '+