From 5388c862607ec4f25f3e7ad23ab858b696bde1a1 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Mon, 18 May 2015 11:13:44 +0200 Subject: [PATCH] zramctl: support /sys/block/zram/mm_stat Linux >= 4.1 provides all memory related statistics by one file. Signed-off-by: Karel Zak --- sys-utils/zramctl.c | 91 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 78 insertions(+), 13 deletions(-) diff --git a/sys-utils/zramctl.c b/sys-utils/zramctl.c index 2d47e5630..312d236e4 100644 --- a/sys-utils/zramctl.c +++ b/sys-utils/zramctl.c @@ -34,6 +34,7 @@ #include "sysfs.h" #include "optutils.h" #include "ismounted.h" +#include "strv.h" /*#define CONFIG_ZRAM_DEBUG*/ @@ -78,9 +79,33 @@ static const struct colinfo infos[] = { static int columns[ARRAY_SIZE(infos) * 2] = {-1}; static int ncolumns; +enum { + MM_ORIG_DATA_SIZE = 0, + MM_COMPR_DATA_SIZE, + MM_MEM_USED_TOTAL, + MM_MEM_LIMIT, + MM_MEM_USED_MAX, + MM_ZERO_PAGES, + MM_NUM_MIGRATED +}; + +static const char *mm_stat_names[] = { + [MM_ORIG_DATA_SIZE] = "orig_data_size", + [MM_COMPR_DATA_SIZE] = "compr_data_size", + [MM_MEM_USED_TOTAL] = "mem_used_total", + [MM_MEM_LIMIT] = "mem_limit", + [MM_MEM_USED_MAX] = "mem_used_max", + [MM_ZERO_PAGES] = "zero_pages", + [MM_NUM_MIGRATED] = "num_migrated" +}; + + struct zram { char devname[32]; struct sysfs_cxt sysfs; + char **mm_stat; + + unsigned int mm_stat_probed : 1; }; #define ZRAM_EMPTY { .devname = { '\0' }, .sysfs = UL_SYSFSCXT_EMPTY } @@ -145,6 +170,8 @@ static void free_zram(struct zram *z) return; DBG(fprintf(stderr, "free: %p", z)); sysfs_deinit(&z->sysfs); + + strv_free(z->mm_stat); free(z); } @@ -238,6 +265,53 @@ static struct zram *find_free_zram(void) return z; } +#include "path.h" + +static char *get_mm_stat(struct zram *z, size_t idx, int inbytes) +{ + struct sysfs_cxt *sysfs; + const char *name; + uint64_t num; + + assert(idx < ARRAY_SIZE(mm_stat_names)); + assert(z); + + sysfs = zram_get_sysfs(z); + if (!sysfs) + return NULL; + + /* Linux >= 4.1 uses /sys/block/zram/mm_stat */ + if (!z->mm_stat && !z->mm_stat_probed) { + char *str; + + str = sysfs_strdup(sysfs, "mm_stat"); + if (str) { + z->mm_stat = strv_split(str, " "); + if (strv_length(z->mm_stat) < ARRAY_SIZE(mm_stat_names)) + errx(EXIT_FAILURE, _("Failed to parse mm_stat")); + } + z->mm_stat_probed = 1; + free(str); + + } + + if (z->mm_stat) { + if (inbytes) + return xstrdup(z->mm_stat[idx]); + + num = strtou64_or_err(z->mm_stat[idx], _("Failed to parse mm_stat")); + return size_to_human_string(SIZE_SUFFIX_1LETTER, num); + } + + /* Linux < 4.1 uses /sys/block/zram/ */ + name = mm_stat_names[idx]; + if (inbytes) + return sysfs_strdup(sysfs, name); + else if (sysfs_read_u64(sysfs, name, &num) == 0) + return size_to_human_string(SIZE_SUFFIX_1LETTER, num); + return NULL; +} + static void fill_table_row(struct libscols_table *tb, struct zram *z) { static struct libscols_line *ln; @@ -272,16 +346,10 @@ static void fill_table_row(struct libscols_table *tb, struct zram *z) str = size_to_human_string(SIZE_SUFFIX_1LETTER, num); break; case COL_ORIG_SIZE: - if (inbytes) - str = sysfs_strdup(sysfs, "orig_data_size"); - else if (sysfs_read_u64(sysfs, "orig_data_size", &num) == 0) - str = size_to_human_string(SIZE_SUFFIX_1LETTER, num); + str = get_mm_stat(z, MM_ORIG_DATA_SIZE, inbytes); break; case COL_COMP_SIZE: - if (inbytes) - str = sysfs_strdup(sysfs, "compr_data_size"); - else if (sysfs_read_u64(sysfs, "compr_data_size", &num) == 0) - str = size_to_human_string(SIZE_SUFFIX_1LETTER, num); + str = get_mm_stat(z, MM_COMPR_DATA_SIZE, inbytes); break; case COL_ALGORITHM: { @@ -312,13 +380,10 @@ static void fill_table_row(struct libscols_table *tb, struct zram *z) str = sysfs_strdup(sysfs, "max_comp_streams"); break; case COL_ZEROPAGES: - str = sysfs_strdup(sysfs, "zero_pages"); + str = get_mm_stat(z, MM_ZERO_PAGES, 1); break; case COL_MEMTOTAL: - if (inbytes) - str = sysfs_strdup(sysfs, "mem_used_total"); - else if (sysfs_read_u64(sysfs, "mem_used_total", &num) == 0) - str = size_to_human_string(SIZE_SUFFIX_1LETTER, num); + str = get_mm_stat(z, MM_MEM_USED_TOTAL, inbytes); break; }