123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437 |
- // 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_file(filename, state, ZSWAP_STATE_SIZE);
- 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;
- }
|