summaryrefslogtreecommitdiffstats
path: root/src/collectors/debugfs.plugin
diff options
context:
space:
mode:
Diffstat (limited to 'src/collectors/debugfs.plugin')
-rw-r--r--src/collectors/debugfs.plugin/README.md65
-rw-r--r--src/collectors/debugfs.plugin/debugfs_extfrag.c123
-rw-r--r--src/collectors/debugfs.plugin/debugfs_plugin.c250
-rw-r--r--src/collectors/debugfs.plugin/debugfs_plugin.h17
-rw-r--r--src/collectors/debugfs.plugin/debugfs_zswap.c437
-rw-r--r--src/collectors/debugfs.plugin/integrations/linux_zswap.md138
-rw-r--r--src/collectors/debugfs.plugin/integrations/power_capping.md132
-rw-r--r--src/collectors/debugfs.plugin/integrations/system_memory_fragmentation.md136
-rw-r--r--src/collectors/debugfs.plugin/metadata.yaml395
-rw-r--r--src/collectors/debugfs.plugin/sys_devices_virtual_powercap.c217
10 files changed, 1910 insertions, 0 deletions
diff --git a/src/collectors/debugfs.plugin/README.md b/src/collectors/debugfs.plugin/README.md
new file mode 100644
index 000000000..514c8bb61
--- /dev/null
+++ b/src/collectors/debugfs.plugin/README.md
@@ -0,0 +1,65 @@
+# OS provided metrics (debugfs.plugin)
+
+`debugfs.plugin` gathers metrics from the `/sys/kernel/debug` folder on Linux
+systems. [Debugfs](https://docs.kernel.org/filesystems/debugfs.html) exists as an easy way for kernel developers to
+make information available to user space.
+
+This plugin
+is [external](https://github.com/netdata/netdata/tree/master/src/collectors#collector-architecture-and-terminology),
+the netdata daemon spawns it as a long-running independent process.
+
+In detail, it collects metrics from:
+
+- `/sys/kernel/debug/extfrag` (Memory fragmentation index for each order and zone).
+- `/sys/kernel/debug/zswap` ([Zswap](https://www.kernel.org/doc/Documentation/vm/zswap.txt) performance statistics).
+
+## Prerequisites
+
+### Permissions
+
+> No user action required.
+
+The debugfs root directory is accessible only to the root user by default. Netdata
+uses [Linux Capabilities](https://man7.org/linux/man-pages/man7/capabilities.7.html) to give the plugin access
+to debugfs. `CAP_DAC_READ_SEARCH` is added automatically during installation. This capability allows bypassing file read
+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.
+
+## Metrics
+
+| Metric | Scope | Dimensions | Units | Labels |
+|-------------------------------------|:---------:|:---------------------------------------------------------------------------------------:|:------------:|:---------:|
+| mem.fragmentation_index_dma | numa node | order0, order1, order2, order3, order4, order5, order6, order7, order8, order9, order10 | index | numa_node |
+| mem.fragmentation_index_dma32 | numa node | order0, order1, order2, order3, order4, order5, order6, order7, order8, order9, order10 | index | numa_node |
+| mem.fragmentation_index_normal | numa node | order0, order1, order2, order3, order4, order5, order6, order7, order8, order9, order10 | index | numa_node |
+| system.zswap_pool_compression_ratio | | compression_ratio | ratio | |
+| system.zswap_pool_compressed_size | | compressed_size | bytes | |
+| system.zswap_pool_raw_size | | uncompressed_size | bytes | |
+| system.zswap_rejections | | compress_poor, kmemcache_fail, alloc_fail, reclaim_fail | rejections/s | |
+| system.zswap_pool_limit_hit | | limit | events/s | |
+| system.zswap_written_back_raw_bytes | | written_back | bytes/s | |
+| system.zswap_same_filled_raw_size | | same_filled | bytes | |
+| system.zswap_duplicate_entry | | entries | entries/s | |
+
+## Troubleshooting
+
+To troubleshoot issues with the collector, run the `debugfs.plugin` in the terminal. The output
+should give you clues as to why the collector isn't working.
+
+- Navigate to the `plugins.d` directory, usually at `/usr/libexec/netdata/plugins.d/`. If that's not the case on
+ your system, open `netdata.conf` and look for the `plugins` setting under `[directories]`.
+
+ ```bash
+ cd /usr/libexec/netdata/plugins.d/
+ ```
+
+- Switch to the `netdata` user.
+
+ ```bash
+ sudo -u netdata -s
+ ```
+
+- Run the `debugfs.plugin` to debug the collector:
+
+ ```bash
+ ./debugfs.plugin
+ ```
diff --git a/src/collectors/debugfs.plugin/debugfs_extfrag.c b/src/collectors/debugfs.plugin/debugfs_extfrag.c
new file mode 100644
index 000000000..75da4deca
--- /dev/null
+++ b/src/collectors/debugfs.plugin/debugfs_extfrag.c
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "debugfs_plugin.h"
+
+#define NETDATA_ORDER_FRAGMENTATION 11
+
+static char *orders[NETDATA_ORDER_FRAGMENTATION] = { "order0", "order1", "order2", "order3", "order4",
+ "order5", "order6", "order7", "order8", "order9",
+ "order10"
+};
+
+static struct netdata_extrafrag {
+ char *node_zone;
+ uint32_t hash;
+
+ char *id;
+
+ collected_number orders[NETDATA_ORDER_FRAGMENTATION];
+
+ struct netdata_extrafrag *next;
+} *netdata_extrafrags_root = NULL;
+
+static struct netdata_extrafrag *find_or_create_extrafrag(const char *name)
+{
+ struct netdata_extrafrag *extrafrag;
+ uint32_t hash = simple_hash(name);
+
+ // search it, from beginning to the end
+ for (extrafrag = netdata_extrafrags_root ; extrafrag ; extrafrag = extrafrag->next) {
+ if (unlikely(hash == extrafrag->hash && !strcmp(name, extrafrag->node_zone))) {
+ return extrafrag;
+ }
+ }
+
+ extrafrag = callocz(1, sizeof(struct netdata_extrafrag));
+ extrafrag->node_zone = strdupz(name);
+ extrafrag->hash = hash;
+
+ if (netdata_extrafrags_root) {
+ struct netdata_extrafrag *last_node;
+ for (last_node = netdata_extrafrags_root; last_node->next ; last_node = last_node->next);
+
+ last_node->next = extrafrag;
+ } else
+ netdata_extrafrags_root = extrafrag;
+
+
+ return extrafrag;
+}
+
+static void extfrag_send_chart(char *chart_id, collected_number *values)
+{
+ int i;
+ fprintf(stdout, "BEGIN mem.fragmentation_index_%s\n", chart_id);
+ for (i = 0; i < NETDATA_ORDER_FRAGMENTATION; i++) {
+ fprintf(stdout, "SET %s = %lld\n", orders[i], values[i]);
+ }
+ fprintf(stdout, "END\n");
+ fflush(stdout);
+}
+
+int do_debugfs_extfrag(int update_every, const char *name) {
+ static procfile *ff = NULL;
+ static int chart_order = NETDATA_CHART_PRIO_MEM_FRAGMENTATION;
+
+ if (unlikely(!ff)) {
+ char filename[FILENAME_MAX + 1];
+ snprintfz(filename,
+ FILENAME_MAX,
+ "%s%s",
+ netdata_configured_host_prefix,
+ "/sys/kernel/debug/extfrag/extfrag_index");
+
+ ff = procfile_open(filename, " \t,", PROCFILE_FLAG_DEFAULT);
+ if (unlikely(!ff)) return 1;
+ }
+
+ ff = procfile_readall(ff);
+ if (unlikely(!ff)) return 1;
+
+ size_t l, i, j, lines = procfile_lines(ff);
+ for (l = 0; l < lines; l++) {
+ char chart_id[64];
+ char zone_lowercase[32];
+ if (unlikely(procfile_linewords(ff, l) < 15)) continue;
+ char *zone = procfile_lineword(ff, l, 3);
+ strncpyz(zone_lowercase, zone, 31);
+ debugfs2lower(zone_lowercase);
+
+ char *id = procfile_lineword(ff, l, 1);
+ snprintfz(chart_id, 63, "node_%s_%s", id, zone_lowercase);
+ debugfs2lower(chart_id);
+
+ struct netdata_extrafrag *extrafrag = find_or_create_extrafrag(chart_id);
+ collected_number *line_orders = extrafrag->orders;
+ for (i = 4, j = 0 ; i < 15; i++, j++) {
+ NETDATA_DOUBLE value = str2ndd(procfile_lineword(ff, l, i), NULL);
+ line_orders[j] = (collected_number) (value * 1000.0);
+ }
+
+ if (unlikely(!extrafrag->id)) {
+ extrafrag->id = extrafrag->node_zone;
+ fprintf(
+ stdout,
+ "CHART mem.fragmentation_index_%s '' 'Memory fragmentation index for each order' 'index' 'fragmentation' 'mem.fragmentation_index_%s' 'line' %d %d '' 'debugfs.plugin' '%s'\n",
+ extrafrag->node_zone,
+ zone_lowercase,
+ chart_order++, // FIXME: the same zones must have the same order
+ update_every,
+ name);
+ for (i = 0; i < NETDATA_ORDER_FRAGMENTATION; i++) {
+ fprintf(stdout, "DIMENSION '%s' '%s' absolute 1 1000 ''\n", orders[i], orders[i]);
+ }
+ fprintf(stdout,
+ "CLABEL 'numa_node' 'node%s' 1\n"
+ "CLABEL_COMMIT\n",
+ id);
+ }
+ extfrag_send_chart(chart_id, line_orders);
+ }
+
+ return 0;
+}
diff --git a/src/collectors/debugfs.plugin/debugfs_plugin.c b/src/collectors/debugfs.plugin/debugfs_plugin.c
new file mode 100644
index 000000000..94e3db631
--- /dev/null
+++ b/src/collectors/debugfs.plugin/debugfs_plugin.c
@@ -0,0 +1,250 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "debugfs_plugin.h"
+#include "libnetdata/required_dummies.h"
+
+static char *user_config_dir = CONFIG_DIR;
+static char *stock_config_dir = LIBCONFIG_DIR;
+
+static int update_every = 1;
+
+static struct debugfs_module {
+ const char *name;
+
+ int enabled;
+
+ int (*func)(int update_every, const char *name);
+} debugfs_modules[] = {
+ // Memory Fragmentation
+ { .name = "/sys/kernel/debug/extfrag", .enabled = CONFIG_BOOLEAN_YES,
+ .func = do_debugfs_extfrag},
+ { .name = "/sys/kernel/debug/zswap", .enabled = CONFIG_BOOLEAN_YES,
+ .func = do_debugfs_zswap},
+ // Linux powercap metrics is here because it needs privilege to read each RAPL zone
+ { .name = "/sys/devices/virtual/powercap", .enabled = CONFIG_BOOLEAN_YES,
+ .func = do_sys_devices_virtual_powercap},
+
+ // The terminator
+ { .name = NULL, .enabled = CONFIG_BOOLEAN_NO, .func = NULL}
+};
+
+#ifdef HAVE_SYS_CAPABILITY_H
+static int debugfs_check_capabilities()
+{
+ cap_t caps = cap_get_proc();
+ if (!caps) {
+ netdata_log_error("Cannot get current capabilities.");
+ return 0;
+ }
+
+ int ret = 1;
+ cap_flag_value_t cfv = CAP_CLEAR;
+ if (cap_get_flag(caps, CAP_DAC_READ_SEARCH, CAP_EFFECTIVE, &cfv) == -1) {
+ netdata_log_error("Cannot find if CAP_DAC_READ_SEARCH is effective.");
+ ret = 0;
+ } else {
+ if (cfv != CAP_SET) {
+ netdata_log_error("debugfs.plugin should run with CAP_DAC_READ_SEARCH.");
+ ret = 0;
+ }
+ }
+ cap_free(caps);
+
+ return ret;
+}
+#else
+static int debugfs_check_capabilities()
+{
+ return 0;
+}
+#endif
+
+// TODO: This is a function used by 3 different collector, we should do it global (next PR)
+static int debugfs_am_i_running_as_root()
+{
+ uid_t uid = getuid(), euid = geteuid();
+
+ if (uid == 0 || euid == 0) {
+ return 1;
+ }
+
+ return 0;
+}
+
+void debugfs2lower(char *name)
+{
+ while (*name) {
+ *name = tolower(*name);
+ name++;
+ }
+}
+
+// Consiidering our goal to redce binaries, I preferred to copy function, instead to force link with unecessary libs
+const char *debugfs_rrdset_type_name(RRDSET_TYPE chart_type) {
+ switch(chart_type) {
+ case RRDSET_TYPE_LINE:
+ default:
+ return RRDSET_TYPE_LINE_NAME;
+
+ case RRDSET_TYPE_AREA:
+ return RRDSET_TYPE_AREA_NAME;
+
+ case RRDSET_TYPE_STACKED:
+ return RRDSET_TYPE_STACKED_NAME;
+ }
+}
+
+const char *debugfs_rrd_algorithm_name(RRD_ALGORITHM algorithm) {
+ switch(algorithm) {
+ case RRD_ALGORITHM_ABSOLUTE:
+ default:
+ return RRD_ALGORITHM_ABSOLUTE_NAME;
+
+ case RRD_ALGORITHM_INCREMENTAL:
+ return RRD_ALGORITHM_INCREMENTAL_NAME;
+
+ case RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL:
+ return RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL_NAME;
+
+ case RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL:
+ return RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL_NAME;
+ }
+}
+
+int debugfs_check_sys_permission() {
+ int ret = 0;
+
+ char filename[FILENAME_MAX + 1];
+
+ snprintfz(filename, FILENAME_MAX, "%s/sys/kernel/debug/extfrag/extfrag_index", netdata_configured_host_prefix);
+
+ procfile *ff = procfile_open(filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
+ if(!ff) goto dcsp_cleanup;
+
+ ff = procfile_readall(ff);
+ if(!ff) goto dcsp_cleanup;
+
+ ret = 1;
+
+dcsp_cleanup:
+ if (!ret)
+ perror("Cannot open /sys/kernel/debug/extfrag/extfrag_index file");
+ procfile_close(ff);
+ return ret;
+}
+
+static void debugfs_parse_args(int argc, char **argv)
+{
+ int i, freq = 0;
+ for(i = 1; i < argc; i++) {
+ if(!freq) {
+ int n = (int)str2l(argv[i]);
+ if(n > 0) {
+ freq = n;
+ continue;
+ }
+ }
+
+ if(strcmp("test-permissions", argv[i]) == 0 || strcmp("-t", argv[i]) == 0) {
+ if(!debugfs_check_sys_permission()) {
+ exit(2);
+ }
+ printf("OK\n");
+ exit(0);
+ }
+ }
+
+ if(freq > 0) update_every = freq;
+}
+
+int main(int argc, char **argv)
+{
+ clocks_init();
+ nd_log_initialize_for_external_plugins("debugfs.plugin");
+
+ netdata_configured_host_prefix = getenv("NETDATA_HOST_PREFIX");
+ if (verify_netdata_host_prefix(true) == -1)
+ exit(1);
+
+ user_config_dir = getenv("NETDATA_USER_CONFIG_DIR");
+ if (user_config_dir == NULL) {
+ user_config_dir = CONFIG_DIR;
+ }
+
+ stock_config_dir = getenv("NETDATA_STOCK_CONFIG_DIR");
+ if (stock_config_dir == NULL) {
+ // netdata_log_info("NETDATA_CONFIG_DIR is not passed from netdata");
+ stock_config_dir = LIBCONFIG_DIR;
+ }
+
+ // FIXME: should first check if /sys/kernel/debug is mounted
+
+ // FIXME: remove debugfs_check_sys_permission() after https://github.com/netdata/netdata/issues/15048 is fixed
+ if (!debugfs_check_capabilities() && !debugfs_am_i_running_as_root() && !debugfs_check_sys_permission()) {
+ uid_t uid = getuid(), euid = geteuid();
+#ifdef HAVE_SYS_CAPABILITY_H
+ netdata_log_error(
+ "debugfs.plugin should either run as root (now running with uid %u, euid %u) or have special capabilities. "
+ "Without these, debugfs.plugin cannot access /sys/kernel/debug. "
+ "To enable capabilities run: sudo setcap cap_dac_read_search,cap_sys_ptrace+ep %s; "
+ "To enable setuid to root run: sudo chown root:netdata %s; sudo chmod 4750 %s; ",
+ uid,
+ euid,
+ argv[0],
+ argv[0],
+ argv[0]);
+#else
+ netdata_log_error(
+ "debugfs.plugin should either run as root (now running with uid %u, euid %u) or have special capabilities. "
+ "Without these, debugfs.plugin cannot access /sys/kernel/debug."
+ "Your system does not support capabilities. "
+ "To enable setuid to root run: sudo chown root:netdata %s; sudo chmod 4750 %s; ",
+ uid,
+ euid,
+ argv[0],
+ argv[0]);
+#endif
+ exit(1);
+ }
+
+ // if (!debugfs_check_sys_permission()) {
+ // exit(2);
+ // }
+
+ debugfs_parse_args(argc, argv);
+
+ size_t iteration;
+ usec_t step = update_every * USEC_PER_SEC;
+ heartbeat_t hb;
+ heartbeat_init(&hb);
+
+ for (iteration = 0; iteration < 86400; iteration++) {
+ heartbeat_next(&hb, step);
+ int enabled = 0;
+
+ for (int i = 0; debugfs_modules[i].name; i++) {
+ struct debugfs_module *pm = &debugfs_modules[i];
+ if (unlikely(!pm->enabled))
+ continue;
+
+ pm->enabled = !pm->func(update_every, pm->name);
+ if (likely(pm->enabled))
+ enabled++;
+ }
+ if (!enabled) {
+ netdata_log_info("all modules are disabled, exiting...");
+ return 1;
+ }
+
+ fprintf(stdout, "\n");
+ fflush(stdout);
+ if (ferror(stdout) && errno == EPIPE) {
+ netdata_log_error("error writing to stdout: EPIPE. Exiting...");
+ return 1;
+ }
+ }
+
+ fprintf(stdout, "EXIT\n");
+ fflush(stdout);
+ return 0;
+}
diff --git a/src/collectors/debugfs.plugin/debugfs_plugin.h b/src/collectors/debugfs.plugin/debugfs_plugin.h
new file mode 100644
index 000000000..903e4a19e
--- /dev/null
+++ b/src/collectors/debugfs.plugin/debugfs_plugin.h
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#ifndef NETDATA_DEBUGFS_PLUGIN_H
+#define NETDATA_DEBUGFS_PLUGIN_H 1
+
+#include "libnetdata/libnetdata.h"
+#include "collectors/all.h"
+#include "database/rrd.h"
+
+int do_debugfs_extfrag(int update_every, const char *name);
+int do_debugfs_zswap(int update_every, const char *name);
+int do_sys_devices_virtual_powercap(int update_every, const char *name);
+void debugfs2lower(char *name);
+const char *debugfs_rrdset_type_name(RRDSET_TYPE chart_type);
+const char *debugfs_rrd_algorithm_name(RRD_ALGORITHM algorithm);
+
+#endif // NETDATA_DEBUGFS_PLUGIN_H
diff --git a/src/collectors/debugfs.plugin/debugfs_zswap.c b/src/collectors/debugfs.plugin/debugfs_zswap.c
new file mode 100644
index 000000000..e4d956cda
--- /dev/null
+++ b/src/collectors/debugfs.plugin/debugfs_zswap.c
@@ -0,0 +1,437 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "debugfs_plugin.h"
+
+static long system_page_size = 4096;
+
+static collected_number pages_to_bytes(collected_number value)
+{
+ return value * system_page_size;
+}
+
+struct netdata_zswap_metric {
+ const char *filename;
+
+ const char *chart_id;
+ const char *title;
+ const char *units;
+ RRDSET_TYPE charttype;
+ int prio;
+ const char *dimension;
+ RRD_ALGORITHM algorithm;
+ int divisor;
+
+ int enabled;
+ int chart_created;
+
+ collected_number value;
+ collected_number (*convertv)(collected_number v);
+};
+
+static struct netdata_zswap_metric zswap_calculated_metrics[] = {
+ {.filename = "",
+ .chart_id = "pool_compression_ratio",
+ .dimension = "compression_ratio",
+ .units = "ratio",
+ .title = "Zswap compression ratio",
+ .algorithm = RRD_ALGORITHM_ABSOLUTE,
+ .charttype = RRDSET_TYPE_LINE,
+ .enabled = CONFIG_BOOLEAN_YES,
+ .chart_created = CONFIG_BOOLEAN_NO,
+ .prio = NETDATA_CHART_PRIO_MEM_ZSWAP_COMPRESS_RATIO,
+ .divisor = 100,
+ .convertv = NULL,
+ .value = -1},
+};
+
+enum netdata_zswap_calculated {
+ NETDATA_ZSWAP_COMPRESSION_RATIO_CHART,
+};
+
+enum netdata_zwap_independent {
+ NETDATA_ZSWAP_POOL_TOTAL_SIZE,
+ NETDATA_ZSWAP_STORED_PAGES,
+ NETDATA_ZSWAP_POOL_LIMIT_HIT,
+ NETDATA_ZSWAP_WRITTEN_BACK_PAGES,
+ NETDATA_ZSWAP_SAME_FILLED_PAGES,
+ NETDATA_ZSWAP_DUPLICATE_ENTRY,
+
+ // Terminator
+ NETDATA_ZSWAP_SITE_END
+};
+
+static struct netdata_zswap_metric zswap_independent_metrics[] = {
+ // https://elixir.bootlin.com/linux/latest/source/mm/zswap.c
+ {.filename = "/sys/kernel/debug/zswap/pool_total_size",
+ .chart_id = "pool_compressed_size",
+ .dimension = "compressed_size",
+ .units = "bytes",
+ .title = "Zswap compressed bytes currently stored",
+ .algorithm = RRD_ALGORITHM_ABSOLUTE,
+ .charttype = RRDSET_TYPE_AREA,
+ .enabled = CONFIG_BOOLEAN_YES,
+ .chart_created = CONFIG_BOOLEAN_NO,
+ .prio = NETDATA_CHART_PRIO_MEM_ZSWAP_POOL_TOT_SIZE,
+ .divisor = 1,
+ .convertv = NULL,
+ .value = -1},
+ {.filename = "/sys/kernel/debug/zswap/stored_pages",
+ .chart_id = "pool_raw_size",
+ .dimension = "uncompressed_size",
+ .units = "bytes",
+ .title = "Zswap uncompressed bytes currently stored",
+ .algorithm = RRD_ALGORITHM_ABSOLUTE,
+ .charttype = RRDSET_TYPE_AREA,
+ .enabled = CONFIG_BOOLEAN_YES,
+ .chart_created = CONFIG_BOOLEAN_NO,
+ .prio = NETDATA_CHART_PRIO_MEM_ZSWAP_STORED_PAGE,
+ .divisor = 1,
+ .convertv = pages_to_bytes,
+ .value = -1},
+ {.filename = "/sys/kernel/debug/zswap/pool_limit_hit",
+ .chart_id = "pool_limit_hit",
+ .dimension = "limit",
+ .units = "events/s",
+ .title = "Zswap pool limit was reached",
+ .algorithm = RRD_ALGORITHM_INCREMENTAL,
+ .charttype = RRDSET_TYPE_LINE,
+ .enabled = CONFIG_BOOLEAN_YES,
+ .chart_created = CONFIG_BOOLEAN_NO,
+ .prio = NETDATA_CHART_PRIO_MEM_ZSWAP_POOL_LIM_HIT,
+ .divisor = 1,
+ .convertv = NULL,
+ .value = -1},
+ {.filename = "/sys/kernel/debug/zswap/written_back_pages",
+ .chart_id = "written_back_raw_bytes",
+ .dimension = "written_back",
+ .units = "bytes/s",
+ .title = "Zswap uncomressed bytes written back when pool limit was reached",
+ .algorithm = RRD_ALGORITHM_INCREMENTAL,
+ .charttype = RRDSET_TYPE_AREA,
+ .enabled = CONFIG_BOOLEAN_YES,
+ .chart_created = CONFIG_BOOLEAN_NO,
+ .prio = NETDATA_CHART_PRIO_MEM_ZSWAP_WRT_BACK_PAGES,
+ .divisor = 1,
+ .convertv = pages_to_bytes,
+ .value = -1},
+ {.filename = "/sys/kernel/debug/zswap/same_filled_pages",
+ .chart_id = "same_filled_raw_size",
+ .dimension = "same_filled",
+ .units = "bytes",
+ .title = "Zswap same-value filled uncompressed bytes currently stored",
+ .algorithm = RRD_ALGORITHM_ABSOLUTE,
+ .charttype = RRDSET_TYPE_AREA,
+ .enabled = CONFIG_BOOLEAN_YES,
+ .chart_created = CONFIG_BOOLEAN_NO,
+ .prio = NETDATA_CHART_PRIO_MEM_ZSWAP_SAME_FILL_PAGE,
+ .divisor = 1,
+ .convertv = pages_to_bytes,
+ .value = -1},
+ {.filename = "/sys/kernel/debug/zswap/duplicate_entry",
+ .chart_id = "duplicate_entry",
+ .dimension = "duplicate",
+ .units = "entries/s",
+ .title = "Zswap duplicate store was encountered",
+ .algorithm = RRD_ALGORITHM_INCREMENTAL,
+ .charttype = RRDSET_TYPE_LINE,
+ .enabled = CONFIG_BOOLEAN_YES,
+ .chart_created = CONFIG_BOOLEAN_NO,
+ .prio = NETDATA_CHART_PRIO_MEM_ZSWAP_DUPP_ENTRY,
+ .divisor = 1,
+ .convertv = NULL,
+ .value = -1},
+
+ // The terminator
+ {.filename = NULL,
+ .chart_id = NULL,
+ .dimension = NULL,
+ .units = NULL,
+ .title = NULL,
+ .algorithm = RRD_ALGORITHM_ABSOLUTE,
+ .charttype = RRDSET_TYPE_LINE,
+ .enabled = CONFIG_BOOLEAN_NO,
+ .chart_created = CONFIG_BOOLEAN_NO,
+ .prio = -1,
+ .value = -1}};
+
+enum netdata_zswap_rejected {
+ NETDATA_ZSWAP_REJECTED_CHART,
+ NETDATA_ZSWAP_REJECTED_COMPRESS_POOR,
+ NETDATA_ZSWAP_REJECTED_KMEM_FAIL,
+ NETDATA_ZSWAP_REJECTED_RALLOC_FAIL,
+ NETDATA_ZSWAP_REJECTED_RRECLAIM_FAIL,
+
+ // Terminator
+ NETDATA_ZSWAP_REJECTED_END
+};
+
+static struct netdata_zswap_metric zswap_rejected_metrics[] = {
+ {.filename = "/sys/kernel/debug/zswap/",
+ .chart_id = "rejections",
+ .dimension = NULL,
+ .units = "rejections/s",
+ .title = "Zswap rejections",
+ .algorithm = RRD_ALGORITHM_INCREMENTAL,
+ .charttype = RRDSET_TYPE_STACKED,
+ .enabled = CONFIG_BOOLEAN_YES,
+ .chart_created = CONFIG_BOOLEAN_NO,
+ .prio = NETDATA_CHART_PRIO_MEM_ZSWAP_REJECTS,
+ .divisor = 1,
+ .convertv = NULL,
+ .value = -1},
+ {.filename = "/sys/kernel/debug/zswap/reject_compress_poor",
+ .chart_id = "reject_compress_poor",
+ .dimension = "compress_poor",
+ .units = NULL,
+ .title = NULL,
+ .algorithm = RRD_ALGORITHM_INCREMENTAL,
+ .charttype = RRDSET_TYPE_STACKED,
+ .enabled = CONFIG_BOOLEAN_YES,
+ .chart_created = CONFIG_BOOLEAN_NO,
+ .prio = NETDATA_CHART_PRIO_MEM_ZSWAP_REJECTS,
+ .divisor = 1,
+ .convertv = NULL,
+ .value = -1},
+ {.filename = "/sys/kernel/debug/zswap/reject_kmemcache_fail",
+ .chart_id = "reject_kmemcache_fail",
+ .dimension = "kmemcache_fail",
+ .units = NULL,
+ .title = NULL,
+ .algorithm = RRD_ALGORITHM_INCREMENTAL,
+ .charttype = RRDSET_TYPE_STACKED,
+ .enabled = CONFIG_BOOLEAN_YES,
+ .chart_created = CONFIG_BOOLEAN_NO,
+ .prio = NETDATA_CHART_PRIO_MEM_ZSWAP_REJECTS,
+ .divisor = 1,
+ .convertv = NULL,
+ .value = -1},
+ {.filename = "/sys/kernel/debug/zswap/reject_alloc_fail",
+ .chart_id = "reject_alloc_fail",
+ .dimension = "alloc_fail",
+ .units = NULL,
+ .title = NULL,
+ .algorithm = RRD_ALGORITHM_INCREMENTAL,
+ .charttype = RRDSET_TYPE_STACKED,
+ .enabled = CONFIG_BOOLEAN_YES,
+ .chart_created = CONFIG_BOOLEAN_NO,
+ .prio = NETDATA_CHART_PRIO_MEM_ZSWAP_REJECTS,
+ .divisor = 1,
+ .convertv = NULL,
+ .value = -1},
+ {.filename = "/sys/kernel/debug/zswap/reject_reclaim_fail",
+ .chart_id = "reject_reclaim_fail",
+ .dimension = "reclaim_fail",
+ .units = NULL,
+ .title = NULL,
+ .algorithm = RRD_ALGORITHM_INCREMENTAL,
+ .charttype = RRDSET_TYPE_STACKED,
+ .enabled = CONFIG_BOOLEAN_YES,
+ .chart_created = CONFIG_BOOLEAN_NO,
+ .prio = NETDATA_CHART_PRIO_MEM_ZSWAP_REJECTS,
+ .divisor = 1,
+ .convertv = NULL,
+ .value = -1},
+
+ // The terminator
+ {.filename = NULL,
+ .chart_id = NULL,
+ .dimension = NULL,
+ .units = NULL,
+ .title = NULL,
+ .algorithm = RRD_ALGORITHM_ABSOLUTE,
+ .charttype = RRDSET_TYPE_STACKED,
+ .enabled = CONFIG_BOOLEAN_NO,
+ .chart_created = CONFIG_BOOLEAN_NO,
+ .prio = -1,
+ .value = -1}};
+
+int zswap_collect_data(struct netdata_zswap_metric *metric)
+{
+ char filename[FILENAME_MAX + 1];
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, metric->filename);
+
+ if (read_single_number_file(filename, (unsigned long long *)&metric->value)) {
+ netdata_log_error("Cannot read file %s", filename);
+ return 1;
+ }
+
+ if (metric->convertv)
+ metric->value = metric->convertv(metric->value);
+
+ return 0;
+}
+
+static void
+zswap_send_chart(struct netdata_zswap_metric *metric, int update_every, const char *name, const char *option)
+{
+ fprintf(
+ stdout,
+ "CHART mem.zswap_%s '' '%s' '%s' 'zswap' '' '%s' %d %d '%s' 'debugfs.plugin' '%s'\n",
+ metric->chart_id,
+ metric->title,
+ metric->units,
+ debugfs_rrdset_type_name(metric->charttype),
+ metric->prio,
+ update_every,
+ (!option) ? "" : option,
+ name);
+}
+
+static void zswap_send_dimension(struct netdata_zswap_metric *metric)
+{
+ int div = metric->divisor > 0 ? metric->divisor : 1;
+ fprintf(
+ stdout,
+ "DIMENSION '%s' '%s' %s 1 %d ''\n",
+ metric->dimension,
+ metric->dimension,
+ debugfs_rrd_algorithm_name(metric->algorithm),
+ div);
+}
+
+static void zswap_send_begin(struct netdata_zswap_metric *metric)
+{
+ fprintf(stdout, "BEGIN mem.zswap_%s\n", metric->chart_id);
+}
+
+static void zswap_send_set(struct netdata_zswap_metric *metric)
+{
+ fprintf(stdout, "SET %s = %lld\n", metric->dimension, metric->value);
+}
+
+static void zswap_send_end_and_flush()
+{
+ fprintf(stdout, "END\n");
+ fflush(stdout);
+}
+
+static void zswap_independent_chart(struct netdata_zswap_metric *metric, int update_every, const char *name)
+{
+ if (unlikely(!metric->chart_created)) {
+ metric->chart_created = CONFIG_BOOLEAN_YES;
+
+ zswap_send_chart(metric, update_every, name, NULL);
+ zswap_send_dimension(metric);
+ }
+
+ zswap_send_begin(metric);
+ zswap_send_set(metric);
+ zswap_send_end_and_flush();
+}
+
+void zswap_reject_chart(int update_every, const char *name)
+{
+ struct netdata_zswap_metric *metric = &zswap_rejected_metrics[NETDATA_ZSWAP_REJECTED_CHART];
+
+ if (unlikely(!metric->chart_created)) {
+ metric->chart_created = CONFIG_BOOLEAN_YES;
+
+ zswap_send_chart(metric, update_every, name, NULL);
+ for (int i = NETDATA_ZSWAP_REJECTED_COMPRESS_POOR; zswap_rejected_metrics[i].filename; i++) {
+ metric = &zswap_rejected_metrics[i];
+ if (likely(metric->enabled))
+ zswap_send_dimension(metric);
+ }
+ }
+
+ metric = &zswap_rejected_metrics[NETDATA_ZSWAP_REJECTED_CHART];
+ zswap_send_begin(metric);
+ for (int i = NETDATA_ZSWAP_REJECTED_COMPRESS_POOR; zswap_rejected_metrics[i].filename; i++) {
+ metric = &zswap_rejected_metrics[i];
+ if (likely(metric->enabled))
+ zswap_send_set(metric);
+ }
+ zswap_send_end_and_flush();
+}
+
+static void zswap_obsolete_charts(int update_every, const char *name)
+{
+ struct netdata_zswap_metric *metric = NULL;
+
+ for (int i = 0; zswap_independent_metrics[i].filename; i++) {
+ metric = &zswap_independent_metrics[i];
+ if (likely(metric->chart_created))
+ zswap_send_chart(metric, update_every, name, "obsolete");
+ }
+
+ metric = &zswap_rejected_metrics[NETDATA_ZSWAP_REJECTED_CHART];
+ if (likely(metric->chart_created))
+ zswap_send_chart(metric, update_every, name, "obsolete");
+
+ metric = &zswap_calculated_metrics[NETDATA_ZSWAP_COMPRESSION_RATIO_CHART];
+ if (likely(metric->chart_created))
+ zswap_send_chart(metric, update_every, name, "obsolete");
+}
+
+#define ZSWAP_STATE_SIZE 1 // Y or N
+static int debugfs_is_zswap_enabled()
+{
+ char filename[FILENAME_MAX + 1];
+ snprintfz(filename, FILENAME_MAX, "/sys/module/zswap/parameters/enabled"); // host prefix is not needed here
+ char state[ZSWAP_STATE_SIZE + 1];
+
+ int ret = read_txt_file(filename, state, sizeof(state));
+
+ if (unlikely(!ret && !strcmp(state, "Y"))) {
+ return 0;
+ }
+ return 1;
+}
+
+int do_debugfs_zswap(int update_every, const char *name)
+{
+ static int check_if_enabled = 1;
+
+ if (likely(check_if_enabled && debugfs_is_zswap_enabled())) {
+ netdata_log_info("Zswap is disabled");
+ return 1;
+ }
+
+ check_if_enabled = 0;
+
+ system_page_size = sysconf(_SC_PAGESIZE);
+ struct netdata_zswap_metric *metric = NULL;
+ int enabled = 0;
+
+ for (int i = 0; zswap_independent_metrics[i].filename; i++) {
+ metric = &zswap_independent_metrics[i];
+ if (unlikely(!metric->enabled))
+ continue;
+ if (unlikely(!(metric->enabled = !zswap_collect_data(metric))))
+ continue;
+ zswap_independent_chart(metric, update_every, name);
+ enabled++;
+ }
+
+ struct netdata_zswap_metric *metric_size = &zswap_independent_metrics[NETDATA_ZSWAP_POOL_TOTAL_SIZE];
+ struct netdata_zswap_metric *metric_raw_size = &zswap_independent_metrics[NETDATA_ZSWAP_STORED_PAGES];
+ if (metric_size->enabled && metric_raw_size->enabled) {
+ metric = &zswap_calculated_metrics[NETDATA_ZSWAP_COMPRESSION_RATIO_CHART];
+ metric->value = 0;
+ if (metric_size->value > 0)
+ metric->value =
+ (collected_number)((NETDATA_DOUBLE)metric_raw_size->value / (NETDATA_DOUBLE)metric_size->value * 100);
+ zswap_independent_chart(metric, update_every, name);
+ }
+
+ int enabled_rejected = 0;
+ for (int i = NETDATA_ZSWAP_REJECTED_COMPRESS_POOR; zswap_rejected_metrics[i].filename; i++) {
+ metric = &zswap_rejected_metrics[i];
+ if (unlikely(!metric->enabled))
+ continue;
+ if (unlikely(!(metric->enabled = !zswap_collect_data(metric))))
+ continue;
+ enabled++;
+ enabled_rejected++;
+ }
+
+ if (likely(enabled_rejected > 0))
+ zswap_reject_chart(update_every, name);
+
+ if (unlikely(!enabled)) {
+ zswap_obsolete_charts(update_every, name);
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/src/collectors/debugfs.plugin/integrations/linux_zswap.md b/src/collectors/debugfs.plugin/integrations/linux_zswap.md
new file mode 100644
index 000000000..b41a480f9
--- /dev/null
+++ b/src/collectors/debugfs.plugin/integrations/linux_zswap.md
@@ -0,0 +1,138 @@
+<!--startmeta
+custom_edit_url: "https://github.com/netdata/netdata/edit/master/src/collectors/debugfs.plugin/integrations/linux_zswap.md"
+meta_yaml: "https://github.com/netdata/netdata/edit/master/src/collectors/debugfs.plugin/metadata.yaml"
+sidebar_label: "Linux ZSwap"
+learn_status: "Published"
+learn_rel_path: "Collecting Metrics/Linux Systems/Memory"
+most_popular: False
+message: "DO NOT EDIT THIS FILE DIRECTLY, IT IS GENERATED BY THE COLLECTOR'S metadata.yaml FILE"
+endmeta-->
+
+# Linux ZSwap
+
+
+<img src="https://netdata.cloud/img/microchip.svg" width="150"/>
+
+
+Plugin: debugfs.plugin
+Module: /sys/kernel/debug/zswap
+
+<img src="https://img.shields.io/badge/maintained%20by-Netdata-%2300ab44" />
+
+## Overview
+
+Collects zswap performance metrics on Linux systems.
+
+
+Parse data from `debugfs file.
+
+This collector is only supported on the following platforms:
+
+- Linux
+
+This collector only supports collecting metrics from a single instance of this integration.
+
+This integration requires read access to files under `/sys/kernel/debug/zswap`, which are accessible only to the root user by default. Netdata uses Linux Capabilities to give the plugin access to debugfs. `CAP_DAC_READ_SEARCH` is added automatically during installation. This capability allows bypassing file read 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.
+
+
+### Default Behavior
+
+#### Auto-Detection
+
+Assuming that debugfs is mounted and the required permissions are available, this integration will automatically detect whether or not the system is using zswap.
+
+
+#### Limits
+
+The default configuration for this integration does not impose any limits on data collection.
+
+#### Performance Impact
+
+The default configuration for this integration is not expected to impose a significant performance impact on the system.
+
+
+## Metrics
+
+Metrics grouped by *scope*.
+
+The scope defines the instance that the metric belongs to. An instance is uniquely identified by a set of labels.
+
+Monitor the performance statistics of zswap.
+
+### Per Linux ZSwap instance
+
+Global zswap performance metrics.
+
+This scope has no labels.
+
+Metrics:
+
+| Metric | Dimensions | Unit |
+|:------|:----------|:----|
+| system.zswap_pool_compression_ratio | compression_ratio | ratio |
+| system.zswap_pool_compressed_size | compressed_size | bytes |
+| system.zswap_pool_raw_size | uncompressed_size | bytes |
+| system.zswap_rejections | compress_poor, kmemcache_fail, alloc_fail, reclaim_fail | rejections/s |
+| system.zswap_pool_limit_hit | limit | events/s |
+| system.zswap_written_back_raw_bytes | written_back | bytes/s |
+| system.zswap_same_filled_raw_size | same_filled | bytes |
+| system.zswap_duplicate_entry | duplicate | entries/s |
+
+
+
+## Alerts
+
+There are no alerts configured by default for this integration.
+
+
+## Setup
+
+### Prerequisites
+
+#### filesystem
+
+The debugfs filesystem must be mounted on your host for plugin to collect data. You can run the command-line (`sudo mount -t debugfs none /sys/kernel/debug/`) to mount it locally. It is also recommended to modify your fstab (5) avoiding necessity to mount the filesystem before starting netdata.
+
+
+
+### Configuration
+
+#### File
+
+The configuration file name for this integration is `netdata.conf`.
+Configuration for this specific integration is located in the `[plugin:debugfs]` section within that file.
+
+The file format is a modified INI syntax. The general structure is:
+
+```ini
+[section1]
+ option1 = some value
+ option2 = some other value
+
+[section2]
+ option3 = some third value
+```
+You can edit the configuration file using the `edit-config` script from the
+Netdata [config directory](/docs/netdata-agent/configuration/README.md#the-netdata-config-directory).
+
+```bash
+cd /etc/netdata 2>/dev/null || cd /opt/netdata/etc/netdata
+sudo ./edit-config netdata.conf
+```
+#### Options
+
+
+
+<details open><summary>Config options</summary>
+
+| Name | Description | Default | Required |
+|:----|:-----------|:-------|:--------:|
+| update every | Data collection frequency. | 1 | no |
+| command options | Additinal parameters for collector | | no |
+
+</details>
+
+#### Examples
+There are no configuration examples.
+
+
diff --git a/src/collectors/debugfs.plugin/integrations/power_capping.md b/src/collectors/debugfs.plugin/integrations/power_capping.md
new file mode 100644
index 000000000..5acb6bed6
--- /dev/null
+++ b/src/collectors/debugfs.plugin/integrations/power_capping.md
@@ -0,0 +1,132 @@
+<!--startmeta
+custom_edit_url: "https://github.com/netdata/netdata/edit/master/src/collectors/debugfs.plugin/integrations/power_capping.md"
+meta_yaml: "https://github.com/netdata/netdata/edit/master/src/collectors/debugfs.plugin/metadata.yaml"
+sidebar_label: "Power Capping"
+learn_status: "Published"
+learn_rel_path: "Collecting Metrics/Linux Systems/Kernel"
+most_popular: False
+message: "DO NOT EDIT THIS FILE DIRECTLY, IT IS GENERATED BY THE COLLECTOR'S metadata.yaml FILE"
+endmeta-->
+
+# Power Capping
+
+
+<img src="https://netdata.cloud/img/powersupply.svg" width="150"/>
+
+
+Plugin: debugfs.plugin
+Module: intel_rapl
+
+<img src="https://img.shields.io/badge/maintained%20by-Netdata-%2300ab44" />
+
+## Overview
+
+Collects power capping performance metrics on Linux systems.
+
+
+Parse data from `debugfs file.
+
+This collector is only supported on the following platforms:
+
+- Linux
+
+This collector only supports collecting metrics from a single instance of this integration.
+
+This integration requires read access to files under `/sys/devices/virtual/powercap`, which are accessible only to the root user by default. Netdata uses Linux Capabilities to give the plugin access to debugfs. `CAP_DAC_READ_SEARCH` is added automatically during installation. This capability allows bypassing file read 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.
+
+
+### Default Behavior
+
+#### Auto-Detection
+
+Assuming that debugfs is mounted and the required permissions are available, this integration will automatically detect whether or not the system is using zswap.
+
+
+#### Limits
+
+The default configuration for this integration does not impose any limits on data collection.
+
+#### Performance Impact
+
+The default configuration for this integration is not expected to impose a significant performance impact on the system.
+
+
+## Metrics
+
+Metrics grouped by *scope*.
+
+The scope defines the instance that the metric belongs to. An instance is uniquely identified by a set of labels.
+
+Monitor the Intel RAPL zones Consumption.
+
+### Per Power Capping instance
+
+Global Intel RAPL zones.
+
+This scope has no labels.
+
+Metrics:
+
+| Metric | Dimensions | Unit |
+|:------|:----------|:----|
+| cpu.powercap_intel_rapl_zone | Power | Watts |
+| cpu.powercap_intel_rapl_subzones | dram, core, uncore | Watts |
+
+
+
+## Alerts
+
+There are no alerts configured by default for this integration.
+
+
+## Setup
+
+### Prerequisites
+
+#### filesystem
+
+The debugfs filesystem must be mounted on your host for plugin to collect data. You can run the command-line (`sudo mount -t debugfs none /sys/kernel/debug/`) to mount it locally. It is also recommended to modify your fstab (5) avoiding necessity to mount the filesystem before starting netdata.
+
+
+
+### Configuration
+
+#### File
+
+The configuration file name for this integration is `netdata.conf`.
+Configuration for this specific integration is located in the `[plugin:debugfs]` section within that file.
+
+The file format is a modified INI syntax. The general structure is:
+
+```ini
+[section1]
+ option1 = some value
+ option2 = some other value
+
+[section2]
+ option3 = some third value
+```
+You can edit the configuration file using the `edit-config` script from the
+Netdata [config directory](/docs/netdata-agent/configuration/README.md#the-netdata-config-directory).
+
+```bash
+cd /etc/netdata 2>/dev/null || cd /opt/netdata/etc/netdata
+sudo ./edit-config netdata.conf
+```
+#### Options
+
+
+
+<details open><summary>Config options</summary>
+
+| Name | Description | Default | Required |
+|:----|:-----------|:-------|:--------:|
+| update every | Data collection frequency. | 1 | no |
+| command options | Additinal parameters for collector | | no |
+
+</details>
+
+#### Examples
+There are no configuration examples.
+
+
diff --git a/src/collectors/debugfs.plugin/integrations/system_memory_fragmentation.md b/src/collectors/debugfs.plugin/integrations/system_memory_fragmentation.md
new file mode 100644
index 000000000..3c43a592a
--- /dev/null
+++ b/src/collectors/debugfs.plugin/integrations/system_memory_fragmentation.md
@@ -0,0 +1,136 @@
+<!--startmeta
+custom_edit_url: "https://github.com/netdata/netdata/edit/master/src/collectors/debugfs.plugin/integrations/system_memory_fragmentation.md"
+meta_yaml: "https://github.com/netdata/netdata/edit/master/src/collectors/debugfs.plugin/metadata.yaml"
+sidebar_label: "System Memory Fragmentation"
+learn_status: "Published"
+learn_rel_path: "Collecting Metrics/Linux Systems/Memory"
+most_popular: False
+message: "DO NOT EDIT THIS FILE DIRECTLY, IT IS GENERATED BY THE COLLECTOR'S metadata.yaml FILE"
+endmeta-->
+
+# System Memory Fragmentation
+
+
+<img src="https://netdata.cloud/img/microchip.svg" width="150"/>
+
+
+Plugin: debugfs.plugin
+Module: /sys/kernel/debug/extfrag
+
+<img src="https://img.shields.io/badge/maintained%20by-Netdata-%2300ab44" />
+
+## Overview
+
+Collects memory fragmentation statistics from the Linux kernel
+
+Parse data from `debugfs` file
+
+This collector is only supported on the following platforms:
+
+- Linux
+
+This collector only supports collecting metrics from a single instance of this integration.
+
+This integration requires read access to files under `/sys/kernel/debug/extfrag`, which are accessible only to the root user by default. Netdata uses Linux Capabilities to give the plugin access to debugfs. `CAP_DAC_READ_SEARCH` is added automatically during installation. This capability allows bypassing file read 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.
+
+
+### Default Behavior
+
+#### Auto-Detection
+
+Assuming that debugfs is mounted and the required permissions are available, this integration will automatically run by default.
+
+
+#### Limits
+
+The default configuration for this integration does not impose any limits on data collection.
+
+#### Performance Impact
+
+The default configuration for this integration is not expected to impose a significant performance impact on the system.
+
+
+## Metrics
+
+Metrics grouped by *scope*.
+
+The scope defines the instance that the metric belongs to. An instance is uniquely identified by a set of labels.
+
+Monitor the overall memory fragmentation of the system.
+
+### Per node
+
+Memory fragmentation statistics for each NUMA node in the system.
+
+Labels:
+
+| Label | Description |
+|:-----------|:----------------|
+| numa_node | The NUMA node the metrics are associated with. |
+
+Metrics:
+
+| Metric | Dimensions | Unit |
+|:------|:----------|:----|
+| mem.fragmentation_index_dma | order0, order1, order2, order3, order4, order5, order6, order7, order8, order9, order10 | index |
+| mem.fragmentation_index_dma32 | order0, order1, order2, order3, order4, order5, order6, order7, order8, order9, order10 | index |
+| mem.fragmentation_index_normal | order0, order1, order2, order3, order4, order5, order6, order7, order8, order9, order10 | index |
+
+
+
+## Alerts
+
+There are no alerts configured by default for this integration.
+
+
+## Setup
+
+### Prerequisites
+
+#### filesystem
+
+The debugfs filesystem must be mounted on your host for plugin to collect data. You can run the command-line (`sudo mount -t debugfs none /sys/kernel/debug/`) to mount it locally. It is also recommended to modify your fstab (5) avoiding necessity to mount the filesystem before starting netdata.
+
+
+
+### Configuration
+
+#### File
+
+The configuration file name for this integration is `netdata.conf`.
+Configuration for this specific integration is located in the `[plugin:debugfs]` section within that file.
+
+The file format is a modified INI syntax. The general structure is:
+
+```ini
+[section1]
+ option1 = some value
+ option2 = some other value
+
+[section2]
+ option3 = some third value
+```
+You can edit the configuration file using the `edit-config` script from the
+Netdata [config directory](/docs/netdata-agent/configuration/README.md#the-netdata-config-directory).
+
+```bash
+cd /etc/netdata 2>/dev/null || cd /opt/netdata/etc/netdata
+sudo ./edit-config netdata.conf
+```
+#### Options
+
+
+
+<details open><summary>Config options</summary>
+
+| Name | Description | Default | Required |
+|:----|:-----------|:-------|:--------:|
+| update every | Data collection frequency. | 1 | no |
+| command options | Additinal parameters for collector | | no |
+
+</details>
+
+#### Examples
+There are no configuration examples.
+
+
diff --git a/src/collectors/debugfs.plugin/metadata.yaml b/src/collectors/debugfs.plugin/metadata.yaml
new file mode 100644
index 000000000..d3bf0a0d8
--- /dev/null
+++ b/src/collectors/debugfs.plugin/metadata.yaml
@@ -0,0 +1,395 @@
+plugin_name: debugfs.plugin
+modules:
+ - meta:
+ plugin_name: debugfs.plugin
+ module_name: /sys/kernel/debug/extfrag
+ monitored_instance:
+ name: System Memory Fragmentation
+ link: 'https://www.kernel.org/doc/html/next/admin-guide/sysctl/vm.html'
+ categories:
+ - data-collection.linux-systems.memory-metrics
+ icon_filename: 'microchip.svg'
+ related_resources:
+ integrations:
+ list: []
+ info_provided_to_referring_integrations:
+ description: ''
+ keywords:
+ - extfrag
+ - extfrag_threshold
+ - memory fragmentation
+ most_popular: false
+ overview:
+ data_collection:
+ metrics_description: 'Collects memory fragmentation statistics from the Linux kernel'
+ method_description: 'Parse data from `debugfs` file'
+ supported_platforms:
+ include:
+ - Linux
+ exclude: []
+ multi_instance: false
+ additional_permissions:
+ description: >
+ This integration requires read access to files under `/sys/kernel/debug/extfrag`, which are accessible
+ only to the root user by default. Netdata uses Linux Capabilities to give the plugin access to
+ debugfs. `CAP_DAC_READ_SEARCH` is added automatically during installation. This capability allows bypassing
+ file read 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.
+ default_behavior:
+ auto_detection:
+ description: >
+ Assuming that debugfs is mounted and the required permissions are available, this integration will
+ automatically run by default.
+ limits:
+ description: ''
+ performance_impact:
+ description: ''
+ setup:
+ prerequisites:
+ list:
+ - title: 'filesystem'
+ description: >
+ The debugfs filesystem must be mounted on your host for plugin to collect data.
+ You can run the command-line (`sudo mount -t debugfs none /sys/kernel/debug/`) to mount it locally.
+ It is also recommended to modify your fstab (5) avoiding necessity to mount the filesystem
+ before starting netdata.
+ configuration:
+ file:
+ name: 'netdata.conf'
+ section_name: '[plugin:debugfs]'
+ description: 'This is netdata main configuration file.'
+ options:
+ description: ''
+ folding:
+ title: 'Config options'
+ enabled: true
+ list:
+ - name: update every
+ description: Data collection frequency.
+ default_value: 1
+ required: false
+ - name: command options
+ description: Additinal parameters for collector
+ default_value: ""
+ required: false
+ examples:
+ folding:
+ enabled: true
+ title: ''
+ list: []
+ troubleshooting:
+ problems:
+ list: []
+ alerts: []
+ metrics:
+ folding:
+ title: Metrics
+ enabled: false
+ description: "Monitor the overall memory fragmentation of the system."
+ availability: []
+ scopes:
+ - name: node
+ description: "Memory fragmentation statistics for each NUMA node in the system."
+ labels:
+ - name: numa_node
+ description: The NUMA node the metrics are associated with.
+ metrics:
+ - name: mem.fragmentation_index_dma
+ description: Memory fragmentation index for each order
+ unit: "index"
+ chart_type: line
+ dimensions:
+ - name: order0
+ - name: order1
+ - name: order2
+ - name: order3
+ - name: order4
+ - name: order5
+ - name: order6
+ - name: order7
+ - name: order8
+ - name: order9
+ - name: order10
+ - name: mem.fragmentation_index_dma32
+ description: Memory fragmentation index for each order
+ unit: "index"
+ chart_type: line
+ dimensions:
+ - name: order0
+ - name: order1
+ - name: order2
+ - name: order3
+ - name: order4
+ - name: order5
+ - name: order6
+ - name: order7
+ - name: order8
+ - name: order9
+ - name: order10
+ - name: mem.fragmentation_index_normal
+ description: Memory fragmentation index for each order
+ unit: "index"
+ chart_type: line
+ dimensions:
+ - name: order0
+ - name: order1
+ - name: order2
+ - name: order3
+ - name: order4
+ - name: order5
+ - name: order6
+ - name: order7
+ - name: order8
+ - name: order9
+ - name: order10
+ - meta:
+ plugin_name: debugfs.plugin
+ module_name: /sys/kernel/debug/zswap
+ monitored_instance:
+ name: Linux ZSwap
+ link: 'https://www.kernel.org/doc/html/latest/admin-guide/mm/zswap.html'
+ categories:
+ - data-collection.linux-systems.memory-metrics
+ icon_filename: 'microchip.svg'
+ related_resources:
+ integrations:
+ list: []
+ info_provided_to_referring_integrations:
+ description: ''
+ keywords:
+ - swap
+ - zswap
+ - frontswap
+ - swap cache
+ most_popular: false
+ overview:
+ data_collection:
+ metrics_description: >
+ Collects zswap performance metrics on Linux systems.
+ method_description: 'Parse data from `debugfs file.'
+ supported_platforms:
+ include:
+ - Linux
+ exclude: []
+ multi_instance: false
+ additional_permissions:
+ description: >
+ This integration requires read access to files under `/sys/kernel/debug/zswap`, which are accessible
+ only to the root user by default. Netdata uses Linux Capabilities to give the plugin access to
+ debugfs. `CAP_DAC_READ_SEARCH` is added automatically during installation. This capability allows bypassing
+ file read 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.
+ default_behavior:
+ auto_detection:
+ description: >
+ Assuming that debugfs is mounted and the required permissions are available, this integration will
+ automatically detect whether or not the system is using zswap.
+ limits:
+ description: ''
+ performance_impact:
+ description: ''
+ setup:
+ prerequisites:
+ list:
+ - title: 'filesystem'
+ description: >
+ The debugfs filesystem must be mounted on your host for plugin to collect data.
+ You can run the command-line (`sudo mount -t debugfs none /sys/kernel/debug/`) to mount it locally.
+ It is also recommended to modify your fstab (5) avoiding necessity to mount the filesystem
+ before starting netdata.
+ configuration:
+ file:
+ name: 'netdata.conf'
+ section_name: '[plugin:debugfs]'
+ description: 'This is netdata main configuration file.'
+ options:
+ description: ''
+ folding:
+ title: 'Config options'
+ enabled: true
+ list:
+ - name: update every
+ description: Data collection frequency.
+ default_value: 1
+ required: false
+ - name: command options
+ description: Additinal parameters for collector
+ default_value: ""
+ required: false
+ examples:
+ folding:
+ enabled: true
+ title: ''
+ list: []
+ troubleshooting:
+ problems:
+ list: []
+ alerts: []
+ metrics:
+ folding:
+ title: Metrics
+ enabled: false
+ description: "Monitor the performance statistics of zswap."
+ availability: []
+ scopes:
+ - name: global
+ description: "Global zswap performance metrics."
+ labels: []
+ metrics:
+ - name: system.zswap_pool_compression_ratio
+ description: Zswap compression ratio
+ unit: "ratio"
+ chart_type: line
+ dimensions:
+ - name: compression_ratio
+ - name: system.zswap_pool_compressed_size
+ description: Zswap compressed bytes currently stored
+ unit: "bytes"
+ chart_type: area
+ dimensions:
+ - name: compressed_size
+ - name: system.zswap_pool_raw_size
+ description: Zswap uncompressed bytes currently stored
+ unit: "bytes"
+ chart_type: area
+ dimensions:
+ - name: uncompressed_size
+ - name: system.zswap_rejections
+ description: Zswap rejections
+ unit: "rejections/s"
+ chart_type: stacked
+ dimensions:
+ - name: compress_poor
+ - name: kmemcache_fail
+ - name: alloc_fail
+ - name: reclaim_fail
+ - name: system.zswap_pool_limit_hit
+ description: Zswap pool limit was reached
+ unit: "events/s"
+ chart_type: line
+ dimensions:
+ - name: limit
+ - name: system.zswap_written_back_raw_bytes
+ description: Zswap uncomressed bytes written back when pool limit was reached
+ unit: "bytes/s"
+ chart_type: area
+ dimensions:
+ - name: written_back
+ - name: system.zswap_same_filled_raw_size
+ description: Zswap same-value filled uncompressed bytes currently stored
+ unit: "bytes"
+ chart_type: area
+ dimensions:
+ - name: same_filled
+ - name: system.zswap_duplicate_entry
+ description: Zswap duplicate store was encountered
+ unit: "entries/s"
+ chart_type: line
+ dimensions:
+ - name: duplicate
+ - meta:
+ plugin_name: debugfs.plugin
+ module_name: intel_rapl
+ monitored_instance:
+ name: Power Capping
+ link: 'https://www.kernel.org/doc/html/next/power/powercap/powercap.html'
+ categories:
+ - data-collection.linux-systems.kernel-metrics
+ icon_filename: 'powersupply.svg'
+ related_resources:
+ integrations:
+ list: []
+ info_provided_to_referring_integrations:
+ description: ''
+ keywords:
+ - power capping
+ - energy
+ most_popular: false
+ overview:
+ data_collection:
+ metrics_description: >
+ Collects power capping performance metrics on Linux systems.
+ method_description: 'Parse data from `debugfs file.'
+ supported_platforms:
+ include:
+ - Linux
+ exclude: []
+ multi_instance: false
+ additional_permissions:
+ description: >
+ This integration requires read access to files under `/sys/devices/virtual/powercap`, which are accessible
+ only to the root user by default. Netdata uses Linux Capabilities to give the plugin access to
+ debugfs. `CAP_DAC_READ_SEARCH` is added automatically during installation. This capability allows bypassing
+ file read 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.
+ default_behavior:
+ auto_detection:
+ description: >
+ Assuming that debugfs is mounted and the required permissions are available, this integration will
+ automatically detect whether or not the system is using zswap.
+ limits:
+ description: ''
+ performance_impact:
+ description: ''
+ setup:
+ prerequisites:
+ list:
+ - title: 'filesystem'
+ description: >
+ The debugfs filesystem must be mounted on your host for plugin to collect data.
+ You can run the command-line (`sudo mount -t debugfs none /sys/kernel/debug/`) to mount it locally.
+ It is also recommended to modify your fstab (5) avoiding necessity to mount the filesystem
+ before starting netdata.
+ configuration:
+ file:
+ name: 'netdata.conf'
+ section_name: '[plugin:debugfs]'
+ description: 'This is netdata main configuration file.'
+ options:
+ description: ''
+ folding:
+ title: 'Config options'
+ enabled: true
+ list:
+ - name: update every
+ description: Data collection frequency.
+ default_value: 1
+ required: false
+ - name: command options
+ description: Additinal parameters for collector
+ default_value: ""
+ required: false
+ examples:
+ folding:
+ enabled: true
+ title: ''
+ list: []
+ troubleshooting:
+ problems:
+ list: []
+ alerts: []
+ metrics:
+ folding:
+ title: Metrics
+ enabled: false
+ description: "Monitor the Intel RAPL zones Consumption."
+ availability: []
+ scopes:
+ - name: global
+ description: "Global Intel RAPL zones."
+ labels: []
+ metrics:
+ - name: cpu.powercap_intel_rapl_zone
+ description: Intel RAPL Zone Power Consumption
+ unit: "Watts"
+ chart_type: line
+ dimensions:
+ - name: Power
+ - name: cpu.powercap_intel_rapl_subzones
+ description: Intel RAPL Subzones Power Consumption
+ unit: "Watts"
+ chart_type: line
+ dimensions:
+ - name: dram
+ - name: core
+ - name: uncore
diff --git a/src/collectors/debugfs.plugin/sys_devices_virtual_powercap.c b/src/collectors/debugfs.plugin/sys_devices_virtual_powercap.c
new file mode 100644
index 000000000..a5dfb7550
--- /dev/null
+++ b/src/collectors/debugfs.plugin/sys_devices_virtual_powercap.c
@@ -0,0 +1,217 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "debugfs_plugin.h"
+
+struct zone_t {
+ char *zone_chart_id;
+ char *subzone_chart_id;
+ char *name;
+ char *path;
+
+ unsigned long long max_energy_range_uj;
+ unsigned long long energy_uj;
+
+ struct zone_t *subzones;
+
+ struct zone_t *prev, *next;
+};
+
+static struct zone_t *rapl_zones = NULL;
+
+static bool get_measurement(const char *path, unsigned long long *energy_uj) {
+ return read_single_number_file(path, energy_uj) == 0;
+}
+
+static struct zone_t *get_rapl_zone(const char *control_type __maybe_unused, struct zone_t *parent __maybe_unused, const char *dirname) {
+ char temp[FILENAME_MAX + 1];
+ snprintfz(temp, FILENAME_MAX, "%s/%s", dirname, "name");
+
+ char name[FILENAME_MAX + 1] = "";
+ if (read_txt_file(temp, name, sizeof(name)) != 0)
+ return NULL;
+
+ char *trimmed = trim(name);
+ if (unlikely(trimmed == NULL || trimmed[0] == 0))
+ return NULL;
+
+ snprintfz(temp, FILENAME_MAX, "%s/%s", dirname, "max_energy_range_uj");
+ unsigned long long max_energy_range_uj = 0;
+ if (unlikely(read_single_number_file(temp, &max_energy_range_uj) != 0)) {
+ collector_error("Cannot read %s", temp);
+ return NULL;
+ }
+
+ snprintfz(temp, FILENAME_MAX, "%s/%s", dirname, "energy_uj");
+ unsigned long long energy_uj;
+ if (unlikely(!get_measurement(temp, &energy_uj))) {
+ collector_info("%s: Cannot read %s", trimmed, temp);
+ return NULL;
+ }
+
+ struct zone_t *zone = callocz(1, sizeof(*zone));
+
+ zone->name = strdupz(trimmed);
+ zone->path = strdupz(temp);
+
+ zone->max_energy_range_uj = max_energy_range_uj;
+ zone->energy_uj = energy_uj;
+
+ collector_info("Found zone: \"%s\"", zone->name);
+
+ return zone;
+}
+
+static struct zone_t *look_for_rapl_zones(const char *control_type, struct zone_t *parent, const char *path, int depth) {
+ if(depth > 2)
+ return NULL;
+
+ struct zone_t *base = NULL;
+
+ DIR *dir = opendir(path);
+ if (unlikely(dir == NULL))
+ return NULL;
+
+ struct dirent *de = NULL;
+ while ((de = readdir(dir))) {
+ if (de->d_type != DT_DIR || de->d_name[0] == '.')
+ continue;
+
+ if(strncmp(de->d_name, "intel-rapl:", 11) != 0)
+ continue;
+
+ char zone_path[FILENAME_MAX + 1];
+ snprintfz(zone_path, FILENAME_MAX, "%s/%s", path, de->d_name);
+
+ struct zone_t *zone = get_rapl_zone(control_type, parent, zone_path);
+ if(zone) {
+ DOUBLE_LINKED_LIST_APPEND_ITEM_UNSAFE(base, zone, prev, next);
+
+ if(!parent)
+ zone->subzones = look_for_rapl_zones(control_type, zone, zone_path, depth + 1);
+ }
+ }
+
+ closedir(dir);
+ return base;
+}
+
+static struct zone_t *get_main_rapl_zones(void) {
+ struct zone_t *base = NULL;
+
+ char dirname[FILENAME_MAX + 1];
+ snprintfz(dirname, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/devices/virtual/powercap");
+
+ DIR *dir = opendir(dirname);
+ if (unlikely(dir == NULL))
+ return 0;
+
+ struct dirent *de = NULL;
+ while ((de = readdir(dir))) {
+ if (de->d_type != DT_DIR || de->d_name[0] == '.')
+ continue;
+
+ if(strncmp(de->d_name, "intel-rapl", 10) != 0)
+ continue;
+
+ char control_type_path[FILENAME_MAX + 1];
+ snprintfz(control_type_path, FILENAME_MAX, "%s/%s", dirname, de->d_name);
+
+ collector_info("Looking at control type \"%s\"", de->d_name);
+ struct zone_t *zone = look_for_rapl_zones(de->d_name, NULL, control_type_path, 0);
+ if(zone)
+ DOUBLE_LINKED_LIST_APPEND_LIST_UNSAFE(base, zone, prev, next);
+ }
+ closedir(dir);
+
+ return base;
+}
+
+int do_sys_devices_virtual_powercap(int update_every, const char *name __maybe_unused) {
+
+ if (unlikely(!rapl_zones)) {
+ rapl_zones = get_main_rapl_zones();
+ if (unlikely(!rapl_zones)) {
+ collector_info("Failed to find powercap zones.");
+ return 1;
+ }
+ }
+
+ for(struct zone_t *zone = rapl_zones; zone ; zone = zone->next) {
+ if(!zone->zone_chart_id) {
+ char id[1000 + 1];
+ snprintf(id, 1000, "cpu.powercap_intel_rapl_zone_%s", zone->name);
+ zone->zone_chart_id = strdupz(id);
+
+ fprintf(stdout,
+ "CHART '%s' '' 'Intel RAPL Zone Power Consumption' 'Watts' 'powercap' '%s' '%s' %d %d '' 'debugfs.plugin' 'intel_rapl'\n",
+ zone->zone_chart_id,
+ "cpu.powercap_intel_rapl_zone",
+ debugfs_rrdset_type_name(RRDSET_TYPE_LINE),
+ NETDATA_CHART_PRIO_POWERCAP,
+ update_every);
+
+ fprintf(stdout,
+ "CLABEL 'zone' '%s' 1\n"
+ "CLABEL_COMMIT\n",
+ zone->name);
+
+ fprintf(stdout,
+ "DIMENSION 'power' '' %s 1 1000000 ''\n",
+ debugfs_rrd_algorithm_name(RRD_ALGORITHM_INCREMENTAL));
+
+ // for the sub-zones
+ snprintf(id, 1000, "cpu.powercap_intel_rapl_subzones_%s", zone->name);
+ zone->subzone_chart_id = strdupz(id);
+ fprintf(stdout,
+ "CHART '%s' '' 'Intel RAPL Subzones Power Consumption' 'Watts' 'powercap' '%s' '%s' %d %d '' 'debugfs.plugin' 'intel_rapl'\n",
+ zone->subzone_chart_id,
+ "cpu.powercap_intel_rapl_subzones",
+ debugfs_rrdset_type_name(RRDSET_TYPE_LINE),
+ NETDATA_CHART_PRIO_POWERCAP + 1,
+ update_every);
+
+ fprintf(stdout,
+ "CLABEL 'zone' '%s' 1\n"
+ "CLABEL_COMMIT\n",
+ zone->name);
+
+ for(struct zone_t *subzone = zone->subzones; subzone ; subzone = subzone->next) {
+ fprintf(stdout,
+ "DIMENSION '%s' '' %s 1 1000000 ''\n",
+ subzone->name,
+ debugfs_rrd_algorithm_name(RRD_ALGORITHM_INCREMENTAL));
+ }
+ }
+
+ if(get_measurement(zone->path, &zone->energy_uj)) {
+ fprintf(stdout,
+ "BEGIN '%s'\n"
+ "SET power = %llu\n"
+ "END\n"
+ , zone->zone_chart_id
+ , zone->energy_uj);
+ }
+
+ if(zone->subzones) {
+ fprintf(stdout,
+ "BEGIN '%s'\n",
+ zone->subzone_chart_id);
+
+ for (struct zone_t *subzone = zone->subzones; subzone; subzone = subzone->next) {
+ if(get_measurement(subzone->path, &subzone->energy_uj)) {
+ fprintf(stdout,
+ "SET '%s' = %llu\n",
+ subzone->name,
+ subzone->energy_uj);
+ }
+ }
+
+ fprintf(stdout, "END\n");
+ }
+
+ }
+
+ fflush(stdout);
+
+ return 0;
+}