mirror of
https://github.com/netdata/netdata.git
synced 2025-04-10 16:17:36 +00:00
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>
This commit is contained in:
parent
bdc40c318a
commit
588096c6b6
24 changed files with 1039 additions and 4 deletions
.github
.gitignoreCMakeLists.txtMakefile.amcollectors
configure.accontrib/debian
daemon
netdata-installer.shnetdata.spec.inpackaging
web/gui
4
.github/labeler.yml
vendored
4
.github/labeler.yml
vendored
|
@ -78,6 +78,10 @@ collectors/cups:
|
|||
- collectors/cups.plugin/*
|
||||
- collectors/cups.plugin/**/*
|
||||
|
||||
collectors/debugfs:
|
||||
- collectors/debugfs.plugin/*
|
||||
- collectors/debugfs.plugin/**/*
|
||||
|
||||
collectors/diskspace:
|
||||
- collectors/diskspace.plugin/*
|
||||
- collectors/diskspace.plugin/**/*
|
||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -74,6 +74,9 @@ collectors/ebpf.plugin/reset_netdata_trace.sh
|
|||
!ebpf.plugin/
|
||||
collectors/ebpf.plugin/includes/
|
||||
|
||||
debugfs.plugin
|
||||
!debugfs.plugin/
|
||||
|
||||
# protoc generated files
|
||||
*.pb.cc
|
||||
*.pb.h
|
||||
|
|
|
@ -507,6 +507,13 @@ target_include_directories(libnetdata BEFORE PUBLIC ${GENERATED_CONFIG_H_DIR})
|
|||
set(APPS_PLUGIN_FILES
|
||||
collectors/apps.plugin/apps_plugin.c)
|
||||
|
||||
set(DEBUGFS_PLUGIN_FILES
|
||||
collectors/debugfs.plugin/debugfs_plugin.c
|
||||
collectors/debugfs.plugin/debugfs_plugin.h
|
||||
collectors/debugfs.plugin/debugfs_extfrag.c
|
||||
collectors/debugfs.plugin/debugfs_zswap.c
|
||||
)
|
||||
|
||||
set(FREEBSD_PLUGIN_FILES
|
||||
collectors/freebsd.plugin/plugin_freebsd.c
|
||||
collectors/freebsd.plugin/plugin_freebsd.h
|
||||
|
@ -1363,6 +1370,21 @@ target_include_directories(netdatacli BEFORE PUBLIC ${GENERATED_CONFIG_H_DIR})
|
|||
target_compile_options(netdatacli PUBLIC ${NETDATA_COMMON_CFLAGS})
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# debugfs.plugin
|
||||
|
||||
IF(ENABLE_PLUGIN_DEBUGFS)
|
||||
message(STATUS "debugfs.plugin: enabled")
|
||||
add_executable(debugfs.plugin ${GENERATED_CONFIG_H} ${DEBUGFS_PLUGIN_FILES})
|
||||
target_link_libraries (debugfs.plugin libnetdata ${NETDATA_COMMON_LIBRARIES} ${CAP_LIBRARIES})
|
||||
target_include_directories(debugfs.plugin PUBLIC ${NETDATA_COMMON_INCLUDE_DIRS} ${CAP_INCLUDE_DIRS})
|
||||
target_include_directories(debugfs.plugin BEFORE PUBLIC ${GENERATED_CONFIG_H_DIR})
|
||||
target_compile_options(debugfs.plugin PUBLIC ${NETDATA_COMMON_CFLAGS} ${CAP_CFLAGS_OTHER})
|
||||
ELSE()
|
||||
message(STATUS "debugfs.plugin: disabled")
|
||||
ENDIF()
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# apps.plugin
|
||||
|
||||
|
|
17
Makefile.am
17
Makefile.am
|
@ -212,6 +212,14 @@ APPS_PLUGIN_FILES = \
|
|||
$(LIBNETDATA_FILES) \
|
||||
$(NULL)
|
||||
|
||||
DEBUGFS_PLUGIN_FILES = \
|
||||
collectors/debugfs.plugin/debugfs_plugin.c \
|
||||
collectors/debugfs.plugin/debugfs_plugin.h \
|
||||
collectors/debugfs.plugin/debugfs_extfrag.c \
|
||||
collectors/debugfs.plugin/debugfs_zswap.c \
|
||||
$(LIBNETDATA_FILES) \
|
||||
$(NULL)
|
||||
|
||||
FREEBSD_PLUGIN_FILES = \
|
||||
collectors/freebsd.plugin/plugin_freebsd.c \
|
||||
collectors/freebsd.plugin/plugin_freebsd.h \
|
||||
|
@ -1168,6 +1176,15 @@ if ENABLE_PLUGIN_APPS
|
|||
$(NULL)
|
||||
endif
|
||||
|
||||
if ENABLE_PLUGIN_DEBUGFS
|
||||
plugins_PROGRAMS += debugfs.plugin
|
||||
debugfs_plugin_SOURCES = $(DEBUGFS_PLUGIN_FILES)
|
||||
debugfs_plugin_LDADD = \
|
||||
$(NETDATA_COMMON_LIBS) \
|
||||
$(OPTIONAL_LIBCAP_LIBS) \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
if ENABLE_PLUGIN_CGROUP_NETWORK
|
||||
plugins_PROGRAMS += cgroup-network
|
||||
cgroup_network_SOURCES = $(CGROUP_NETWORK_FILES)
|
||||
|
|
|
@ -8,6 +8,7 @@ SUBDIRS = \
|
|||
cgroups.plugin \
|
||||
charts.d.plugin \
|
||||
cups.plugin \
|
||||
debugfs.plugin \
|
||||
diskspace.plugin \
|
||||
timex.plugin \
|
||||
ioping.plugin \
|
||||
|
|
|
@ -24,8 +24,17 @@
|
|||
#define NETDATA_CHART_PRIO_SYSTEM_PGPGIO 151
|
||||
#define NETDATA_CHART_PRIO_SYSTEM_RAM 200
|
||||
#define NETDATA_CHART_PRIO_SYSTEM_SWAP 201
|
||||
#define NETDATA_CHART_PRIO_SYSTEM_SWAP_CALLS 202
|
||||
#define NETDATA_CHART_PRIO_SYSTEM_SWAPIO 250
|
||||
#define NETDATA_CHART_PRIO_SYSTEM_ZSWAPIO 300
|
||||
#define NETDATA_CHART_PRIO_SYSTEM_ZSWAP_COMPRESS_RATIO 301
|
||||
#define NETDATA_CHART_PRIO_SYSTEM_ZSWAP_POOL_TOT_SIZE 302
|
||||
#define NETDATA_CHART_PRIO_SYSTEM_ZSWAP_STORED_PAGE 303
|
||||
#define NETDATA_CHART_PRIO_SYSTEM_ZSWAP_REJECTS 304
|
||||
#define NETDATA_CHART_PRIO_SYSTEM_ZSWAP_POOL_LIM_HIT 305
|
||||
#define NETDATA_CHART_PRIO_SYSTEM_ZSWAP_WRT_BACK_PAGES 306
|
||||
#define NETDATA_CHART_PRIO_SYSTEM_ZSWAP_SAME_FILL_PAGE 307
|
||||
#define NETDATA_CHART_PRIO_SYSTEM_ZSWAP_DUPP_ENTRY 308
|
||||
#define NETDATA_CHART_PRIO_SYSTEM_NET 500
|
||||
#define NETDATA_CHART_PRIO_SYSTEM_IPV4 500 // freebsd only
|
||||
#define NETDATA_CHART_PRIO_SYSTEM_IP 501
|
||||
|
@ -103,6 +112,7 @@
|
|||
#define NETDATA_CHART_PRIO_MEM_ZRAM_SAVINGS 1601
|
||||
#define NETDATA_CHART_PRIO_MEM_ZRAM_RATIO 1602
|
||||
#define NETDATA_CHART_PRIO_MEM_ZRAM_EFFICIENCY 1603
|
||||
#define NETDATA_CHART_PRIO_MEM_FRAGMENTATION 1700
|
||||
|
||||
// Disks
|
||||
|
||||
|
|
|
@ -89,6 +89,7 @@ ioping: ioping
|
|||
go.d.plugin: *go.d.plugin*
|
||||
slabinfo.plugin: slabinfo.plugin
|
||||
ebpf.plugin: *ebpf.plugin*
|
||||
debugfs.plugin: *debugfs.plugin*
|
||||
|
||||
# agent-service-discovery
|
||||
agent_sd: agent_sd
|
||||
|
|
9
collectors/debugfs.plugin/Makefile.am
Normal file
9
collectors/debugfs.plugin/Makefile.am
Normal file
|
@ -0,0 +1,9 @@
|
|||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
AUTOMAKE_OPTIONS = subdir-objects
|
||||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||
|
||||
dist_noinst_DATA = \
|
||||
README.md \
|
||||
$(NULL)
|
||||
|
65
collectors/debugfs.plugin/README.md
Normal file
65
collectors/debugfs.plugin/README.md
Normal file
|
@ -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/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
|
||||
```
|
123
collectors/debugfs.plugin/debugfs_extfrag.c
Normal file
123
collectors/debugfs.plugin/debugfs_extfrag.c
Normal file
|
@ -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;
|
||||
}
|
244
collectors/debugfs.plugin/debugfs_plugin.c
Normal file
244
collectors/debugfs.plugin/debugfs_plugin.c
Normal file
|
@ -0,0 +1,244 @@
|
|||
// 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},
|
||||
|
||||
// The terminator
|
||||
{ .name = NULL, .enabled = CONFIG_BOOLEAN_NO, .func = NULL}
|
||||
};
|
||||
|
||||
#ifdef HAVE_CAPABILITY
|
||||
static int debugfs_check_capabilities()
|
||||
{
|
||||
cap_t caps = cap_get_proc();
|
||||
if (!caps) {
|
||||
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) {
|
||||
error("Cannot find if CAP_DAC_READ_SEARCH is effective.");
|
||||
ret = 0;
|
||||
} else {
|
||||
if (cfv != CAP_SET) {
|
||||
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)
|
||||
{
|
||||
// debug_flags = D_PROCFILE;
|
||||
stderror = stderr;
|
||||
|
||||
// set the name for logging
|
||||
program_name = "debugfs.plugin";
|
||||
|
||||
// disable syslog for debugfs.plugin
|
||||
error_log_syslog = 0;
|
||||
|
||||
netdata_configured_host_prefix = getenv("NETDATA_HOST_PREFIX");
|
||||
if (verify_netdata_host_prefix() == -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) {
|
||||
// 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_CAPABILITY
|
||||
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
|
||||
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) {
|
||||
info("all modules are disabled, exiting...");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
16
collectors/debugfs.plugin/debugfs_plugin.h
Normal file
16
collectors/debugfs.plugin/debugfs_plugin.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
// 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);
|
||||
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
|
432
collectors/debugfs.plugin/debugfs_zswap.c
Normal file
432
collectors/debugfs.plugin/debugfs_zswap.c
Normal file
|
@ -0,0 +1,432 @@
|
|||
// 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_SYSTEM_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_SYSTEM_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_SYSTEM_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_SYSTEM_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_SYSTEM_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_SYSTEM_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_SYSTEM_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_SYSTEM_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_SYSTEM_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_SYSTEM_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_SYSTEM_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_SYSTEM_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)
|
||||
{
|
||||
int fd;
|
||||
int ret = 0;
|
||||
char buffer[512];
|
||||
|
||||
char filename[FILENAME_MAX + 1];
|
||||
snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, metric->filename);
|
||||
// we are not using profile_open/procfile_read, because they will generate error during runtime.
|
||||
fd = open(filename, O_RDONLY, 0444);
|
||||
if (fd < 0) {
|
||||
error("Cannot open file %s", filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t r = read(fd, buffer, 511);
|
||||
// We expect at list 1 character
|
||||
if (r < 2) {
|
||||
error("Cannot parse file %s", filename);
|
||||
ret = -1;
|
||||
goto zswap_collect_end;
|
||||
}
|
||||
|
||||
// We discard breakline
|
||||
buffer[r - 1] = '\0';
|
||||
metric->value = str2ll(buffer, NULL);
|
||||
|
||||
if (metric->convertv)
|
||||
metric->value = metric->convertv(metric->value);
|
||||
|
||||
zswap_collect_end:
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
zswap_send_chart(struct netdata_zswap_metric *metric, int update_every, const char *name, const char *option)
|
||||
{
|
||||
fprintf(
|
||||
stdout,
|
||||
"CHART system.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 system.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");
|
||||
}
|
||||
|
||||
int do_debugfs_zswap(int update_every, const char *name)
|
||||
{
|
||||
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 (!enabled) {
|
||||
zswap_obsolete_charts(update_every, name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
12
collectors/debugfs.plugin/metrics.csv
Normal file
12
collectors/debugfs.plugin/metrics.csv
Normal file
|
@ -0,0 +1,12 @@
|
|||
metric,scode,dimensions,unit,description,chart_type,labels,plugin,module
|
||||
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
|
||||
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
|
||||
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
|
||||
system.zswap_pool_compression_ratio,,compression_ratio,ratio,Zswap compression ratio,line,,debugfs.plugin,/sys/kernel/debug/zswap
|
||||
system.zswap_pool_compressed_size,,compressed_size,bytes,Zswap compressed bytes currently stored,area,,debugfs.plugin,/sys/kernel/debug/zswap
|
||||
system.zswap_pool_raw_size,,uncompressed_size,bytes,Zswap uncompressed bytes currently stored,area,,debugfs.plugin,/sys/kernel/debug/zswap
|
||||
system.zswap_rejections,,"compress_poor, kmemcache_fail, alloc_fail, reclaim_fail",rejections/s,Zswap rejections,stacked,,debugfs.plugin,/sys/kernel/debug/zswap
|
||||
system.zswap_pool_limit_hit,,limit,events/s,Zswap pool limit was reached,line,,debugfs.plugin,/sys/kernel/debug/zswap
|
||||
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
|
||||
system.zswap_same_filled_raw_size,,same_filled,bytes,Zswap same-value filled uncompressed bytes currently stored,area,,debugfs.plugin,/sys/kernel/debug/zswap
|
||||
system.zswap_duplicate_entry,,duplicate,entries/s,Zswap duplicate store was encountered,line,,debugfs.plugin,/sys/kernel/debug/zswap
|
|
|
@ -752,7 +752,7 @@ static void ebpf_create_swap_charts(int update_every)
|
|||
EBPF_COMMON_DIMENSION_CALL, NETDATA_SYSTEM_SWAP_SUBMENU,
|
||||
NULL,
|
||||
NETDATA_EBPF_CHART_TYPE_LINE,
|
||||
202,
|
||||
NETDATA_CHART_PRIO_SYSTEM_SWAP_CALLS,
|
||||
ebpf_create_global_dimension,
|
||||
swap_publish_aggregated, NETDATA_SWAP_END,
|
||||
update_every, NETDATA_EBPF_MODULE_NAME_SWAP);
|
||||
|
|
16
configure.ac
16
configure.ac
|
@ -1293,6 +1293,21 @@ if test "${build_ml}" = "yes"; then
|
|||
fi
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# debugfs.plugin
|
||||
|
||||
if test "${build_target}" = "linux"; then
|
||||
AC_DEFINE([ENABLE_DEBUGFS_PLUGIN], [1], [debugfs.plugin])
|
||||
enable_plugin_debugfs="yes"
|
||||
else
|
||||
enable_plugin_debugfs="no"
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([if debugfs.plugin should be enabled])
|
||||
AC_MSG_RESULT([${enable_plugin_debugfs}])
|
||||
AM_CONDITIONAL([ENABLE_PLUGIN_DEBUGFS], [test "${enable_plugin_debugfs}" = "yes"])
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# ebpf.plugin
|
||||
|
||||
|
@ -1808,6 +1823,7 @@ AC_CONFIG_FILES([
|
|||
collectors/apps.plugin/Makefile
|
||||
collectors/cgroups.plugin/Makefile
|
||||
collectors/charts.d.plugin/Makefile
|
||||
collectors/debugfs.plugin/Makefile
|
||||
collectors/diskspace.plugin/Makefile
|
||||
collectors/timex.plugin/Makefile
|
||||
collectors/ioping.plugin/Makefile
|
||||
|
|
|
@ -61,6 +61,7 @@ case "$1" in
|
|||
chown -R root:netdata /usr/libexec/netdata/plugins.d
|
||||
setcap cap_dac_read_search,cap_sys_ptrace+ep /usr/libexec/netdata/plugins.d/apps.plugin
|
||||
setcap cap_dac_read_search+ep /usr/libexec/netdata/plugins.d/slabinfo.plugin
|
||||
setcap cap_dac_read_search+ep /usr/libexec/netdata/plugins.d/debugfs.plugin
|
||||
|
||||
if capsh --supports=cap_perfmon 2>/dev/null; then
|
||||
setcap cap_perfmon+ep /usr/libexec/netdata/plugins.d/perf.plugin
|
||||
|
|
|
@ -113,6 +113,7 @@ override_dh_fixperms:
|
|||
# given extra capabilities in the postinst script.
|
||||
#
|
||||
chmod 0750 $(TOP)/usr/libexec/netdata/plugins.d/apps.plugin
|
||||
chmod 0750 $(TOP)/usr/libexec/netdata/plugins.d/debugfs.plugin
|
||||
chmod 0750 $(TOP)/usr/libexec/netdata/plugins.d/perf.plugin
|
||||
chmod 0750 $(TOP)/usr/libexec/netdata/plugins.d/slabinfo.plugin
|
||||
chmod 0750 $(TOP)/usr/libexec/netdata/plugins.d/go.d.plugin
|
||||
|
|
|
@ -115,6 +115,12 @@
|
|||
#define FEAT_APPS_PLUGIN 0
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_DEBUGFS_PLUGIN
|
||||
#define FEAT_DEBUGFS_PLUGIN 1
|
||||
#else
|
||||
#define FEAT_DEBUGFS_PLUGIN 0
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FREEIPMI
|
||||
#define FEAT_IPMI 1
|
||||
#else
|
||||
|
@ -291,6 +297,7 @@ void print_build_info(void) {
|
|||
printf(" apps: %s\n", FEAT_YES_NO(FEAT_APPS_PLUGIN));
|
||||
printf(" cgroup Network Tracking: %s\n", FEAT_YES_NO(FEAT_CGROUP_NET));
|
||||
printf(" CUPS: %s\n", FEAT_YES_NO(FEAT_CUPS));
|
||||
printf(" debugfs: %s\n", FEAT_YES_NO(FEAT_DEBUGFS_PLUGIN));
|
||||
printf(" EBPF: %s\n", FEAT_YES_NO(FEAT_EBPF));
|
||||
printf(" IPMI: %s\n", FEAT_YES_NO(FEAT_IPMI));
|
||||
printf(" NFACCT: %s\n", FEAT_YES_NO(FEAT_NFACCT));
|
||||
|
@ -349,6 +356,7 @@ void print_build_info_json(void) {
|
|||
printf(" \"apps\": %s,\n", FEAT_JSON_BOOL(FEAT_APPS_PLUGIN));
|
||||
printf(" \"cgroup-net\": %s,\n", FEAT_JSON_BOOL(FEAT_CGROUP_NET));
|
||||
printf(" \"cups\": %s,\n", FEAT_JSON_BOOL(FEAT_CUPS));
|
||||
printf(" \"debugfs\": %s,\n", FEAT_JSON_BOOL(FEAT_DEBUGFS_PLUGIN));
|
||||
printf(" \"ebpf\": %s,\n", FEAT_JSON_BOOL(FEAT_EBPF));
|
||||
printf(" \"ipmi\": %s,\n", FEAT_JSON_BOOL(FEAT_IPMI));
|
||||
printf(" \"nfacct\": %s,\n", FEAT_JSON_BOOL(FEAT_NFACCT));
|
||||
|
@ -424,6 +432,9 @@ void analytics_build_info(BUFFER *b) {
|
|||
#ifdef ENABLE_APPS_PLUGIN
|
||||
add_to_bi(b, "apps");
|
||||
#endif
|
||||
#ifdef ENABLE_DEBUGFS_PLUGIN
|
||||
add_to_bi(b, "debugfs");
|
||||
#endif
|
||||
#ifdef HAVE_SETNS
|
||||
add_to_bi(b, "cgroup Network Tracking");
|
||||
#endif
|
||||
|
|
|
@ -1229,6 +1229,23 @@ if [ "$(id -u)" -eq 0 ]; then
|
|||
fi
|
||||
fi
|
||||
|
||||
if [ -f "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/debugfs.plugin" ]; then
|
||||
run chown "root:${NETDATA_GROUP}" "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/debugfs.plugin"
|
||||
capabilities=0
|
||||
if ! iscontainer && command -v setcap 1> /dev/null 2>&1; then
|
||||
run chmod 0750 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/debugfs.plugin"
|
||||
if run setcap cap_dac_read_search+ep "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/debugfs.plugin"; then
|
||||
# if we managed to setcap, but we fail to execute debugfs.plugin setuid to root
|
||||
"${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/debugfs.plugin" -t > /dev/null 2>&1 && capabilities=1 || capabilities=0
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ $capabilities -eq 0 ]; then
|
||||
# fix debugfs.plugin to be setuid to root
|
||||
run chmod 4750 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/debugfs.plugin"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -f "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/freeipmi.plugin" ]; then
|
||||
run chown "root:${NETDATA_GROUP}" "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/freeipmi.plugin"
|
||||
run chmod 4750 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/freeipmi.plugin"
|
||||
|
|
|
@ -280,6 +280,10 @@ install -m 4750 -p freeipmi.plugin "${RPM_BUILD_ROOT}%{_libexecdir}/%{name}/plug
|
|||
# Install apps.plugin
|
||||
install -m 4750 -p apps.plugin "${RPM_BUILD_ROOT}%{_libexecdir}/%{name}/plugins.d/apps.plugin"
|
||||
|
||||
# ###########################################################
|
||||
# Install debugfs.plugin
|
||||
install -m 0750 -p debugfs.plugin "${RPM_BUILD_ROOT}%{_libexecdir}/%{name}/plugins.d/debugfs.plugin"
|
||||
|
||||
# ###########################################################
|
||||
# Install perf.plugin
|
||||
install -m 4750 -p perf.plugin "${RPM_BUILD_ROOT}%{_libexecdir}/%{name}/plugins.d/perf.plugin"
|
||||
|
@ -501,7 +505,10 @@ rm -rf "${RPM_BUILD_ROOT}"
|
|||
# %caps(cap_perfmon=ep) %attr(0750,root,netdata) %{_libexecdir}/%{name}/plugins.d/perf.plugin
|
||||
%caps(cap_sys_admin=ep) %attr(0750,root,netdata) %{_libexecdir}/%{name}/plugins.d/perf.plugin
|
||||
|
||||
# perf plugin
|
||||
# debugfs plugin
|
||||
%caps(cap_dac_read_search=ep) %attr(0750,root,netdata) %{_libexecdir}/%{name}/plugins.d/debugfs.plugin
|
||||
|
||||
# slabinfo plugin
|
||||
%caps(cap_dac_read_search=ep) %attr(0750,root,netdata) %{_libexecdir}/%{name}/plugins.d/slabinfo.plugin
|
||||
|
||||
# go.d.plugin (the capability required for wireguard module)
|
||||
|
|
|
@ -104,7 +104,8 @@ RUN chown -R root:root \
|
|||
chmod 0755 /usr/libexec/netdata/plugins.d/*.plugin && \
|
||||
chmod 4755 \
|
||||
/usr/libexec/netdata/plugins.d/cgroup-network \
|
||||
/usr/libexec/netdata/plugins.d/apps.plugin && \
|
||||
/usr/libexec/netdata/plugins.d/apps.plugin \
|
||||
/usr/libexec/netdata/plugins.d/debugfs.plugin && \
|
||||
if [ -f /usr/libexec/netdata/plugins.d/freeipmi.plugin ]; then \
|
||||
chmod 4755 /usr/libexec/netdata/plugins.d/freeipmi.plugin; \
|
||||
fi && \
|
||||
|
|
|
@ -171,6 +171,7 @@ progress "changing plugins ownership and permissions"
|
|||
if command -v setcap >/dev/null 2>&1; then
|
||||
run setcap "cap_dac_read_search,cap_sys_ptrace=ep" "usr/libexec/netdata/plugins.d/apps.plugin"
|
||||
run setcap "cap_dac_read_search=ep" "usr/libexec/netdata/plugins.d/slabinfo.plugin"
|
||||
run setcap "cap_dac_read_search=ep" "usr/libexec/netdata/plugins.d/debugfs.plugin"
|
||||
|
||||
if command -v capsh >/dev/null 2>&1 && capsh --supports=cap_perfmon 2>/dev/null ; then
|
||||
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
|
|||
|
||||
run setcap "cap_net_admin,cap_net_raw=eip" "usr/libexec/netdata/plugins.d/go.d.plugin"
|
||||
else
|
||||
for x in apps.plugin perf.plugin slabinfo.plugin; do
|
||||
for x in apps.plugin perf.plugin slabinfo.plugin debugfs.plugin; do
|
||||
f="usr/libexec/netdata/plugins.d/${x}"
|
||||
run chown root:${NETDATA_GROUP} "${f}"
|
||||
run chmod 4750 "${f}"
|
||||
|
|
|
@ -883,6 +883,19 @@ netdataDashboard.submenu = {
|
|||
'When the kernel or an application requests some memory, the buddy allocator provides a page that matches closest the request.'
|
||||
},
|
||||
|
||||
'mem.fragmentation': {
|
||||
info: 'These charts show whether the kernel will compact memory or direct reclaim to satisfy a high-order allocation. '+
|
||||
'The extfrag/extfrag_index file in debugfs shows what the fragmentation index for each order is in each zone in the system.' +
|
||||
'Values tending towards 0 imply allocations would fail due to lack of memory, values towards 1000 imply failures are due to ' +
|
||||
'fragmentation and -1 implies that the allocation will succeed as long as watermarks are met.'
|
||||
},
|
||||
|
||||
'system.zswap': {
|
||||
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 ' +
|
||||
'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 ' +
|
||||
'than reading from the swap device, can also improve workload performance.'
|
||||
},
|
||||
|
||||
'ip.ecn': {
|
||||
info: '<a href="https://en.wikipedia.org/wiki/Explicit_Congestion_Notification" target="_blank">Explicit Congestion Notification (ECN)</a> '+
|
||||
'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 = {
|
|||
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.'
|
||||
},
|
||||
|
||||
'system.zswap_rejections': {
|
||||
info: '<p>Zswap rejected pages per access.</p>' +
|
||||
'<p><b>CompressPoor</b> - compressed page was too big for the allocator to store. ' +
|
||||
'<b>KmemcacheFail</b> - number of entry metadata that could not be allocated. ' +
|
||||
'<b>AllocFail</b> - allocator could not get memory. ' +
|
||||
'<b>ReclaimFail</b> - memory cannot be reclaimed (pool limit was reached).</p>'
|
||||
},
|
||||
|
||||
'system.clock_sync_state': {
|
||||
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. '+
|
||||
'An unsynchronized clock may be the result of synchronization issues by the NTP daemon or a hardware clock fault. '+
|
||||
|
|
Loading…
Add table
Reference in a new issue