/* * This file is part of Xfce (https://gitlab.xfce.org). * * zram monitor: local addition, not part of upstream. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES * ARE DISCLAIMED. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include "zram.h" #ifdef __linux__ #include #include #include /* * /sys/block/zramN/mm_stat is a single line of whitespace-separated numbers: * * orig_data_size compr_data_size mem_used_total mem_limit mem_used_max * same_pages pages_compacted huge_pages [huge_pages_since] * * All sizes are in bytes. Only the first three are needed here. * * The file exists only while the device is initialised; an allocated but * unused zramN has no mm_stat, so a failed read is normal, not an error. */ static gboolean read_one_device (const gchar *devname, guint64 *orig, guint64 *compr, guint64 *used) { gchar *path = g_strdup_printf ("/sys/block/%s/mm_stat", devname); gchar *contents = NULL; gboolean ok = FALSE; if (g_file_get_contents (path, &contents, NULL, NULL)) { guint64 o = 0, c = 0, u = 0; if (sscanf (contents, "%" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT, &o, &c, &u) == 3) { *orig = o; *compr = c; *used = u; ok = TRUE; } } g_free (contents); g_free (path); return ok; } /* Walks /sys/block and sums mm_stat over every zram device. */ static gboolean sum_devices (guint64 *orig, guint64 *compr, guint64 *used) { GDir *dir = g_dir_open ("/sys/block", 0, NULL); if (dir == NULL) return FALSE; guint64 t_orig = 0, t_compr = 0, t_used = 0; gboolean found = FALSE; const gchar *name; while ((name = g_dir_read_name (dir)) != NULL) { if (!g_str_has_prefix (name, "zram")) continue; guint64 o = 0, c = 0, u = 0; if (read_one_device (name, &o, &c, &u)) { t_orig += o; t_compr += c; t_used += u; found = TRUE; } } g_dir_close (dir); if (!found) return FALSE; *orig = t_orig; *compr = t_compr; *used = t_used; return TRUE; } static gulong mem_total_kb (void) { gchar *contents = NULL; gulong total = 0; if (g_file_get_contents ("/proc/meminfo", &contents, NULL, NULL)) { const gchar *p = strstr (contents, "MemTotal"); if (p != NULL) sscanf (p + strlen ("MemTotal"), ": %lu", &total); } g_free (contents); return total; } gulong read_zram_phys (void) { guint64 orig = 0, compr = 0, used = 0; if (!sum_devices (&orig, &compr, &used)) return 0; return (gulong) (used / 1024); } gint read_zram (gulong *zram, gulong *phys_kb, gulong *stored_kb, gdouble *ratio) { guint64 orig = 0, compr = 0, used = 0; if (!sum_devices (&orig, &compr, &used)) return -1; *phys_kb = (gulong) (used / 1024); *stored_kb = (gulong) (orig / 1024); *ratio = (compr > 0) ? ((gdouble) orig / (gdouble) compr) : 0.0; gulong total = mem_total_kb (); *zram = (total > 0) ? (*phys_kb * 100 / total) : 0; return 0; } gint read_disk_swap (gulong *total_kb, gulong *used_kb) { gchar *contents = NULL; if (!g_file_get_contents ("/proc/swaps", &contents, NULL, NULL)) return -1; gulong total = 0, used = 0; gchar **lines = g_strsplit (contents, "\n", -1); /* Line 0 is the header: Filename Type Size Used Priority */ for (guint i = 1; lines[i] != NULL; i++) { if (lines[i][0] == '\0') continue; gchar **f = g_strsplit_set (lines[i], " \t", -1); gchar **compact = g_new0 (gchar *, g_strv_length (f) + 1); guint n = 0; /* /proc/swaps is tab-padded, so collapse the empty fields */ for (guint j = 0; f[j] != NULL; j++) if (f[j][0] != '\0') compact[n++] = f[j]; /* Skip zram: its size is the uncompressed one and it costs no disk */ if (n >= 4 && !g_str_has_prefix (compact[0], "/dev/zram")) { total += strtoul (compact[2], NULL, 10); used += strtoul (compact[3], NULL, 10); } g_free (compact); g_strfreev (f); } g_strfreev (lines); g_free (contents); *total_kb = total; *used_kb = used; return 0; } #else /* !__linux__ */ gulong read_zram_phys (void) { return 0; } gint read_zram (gulong *zram, gulong *phys_kb, gulong *stored_kb, gdouble *ratio) { *zram = 0; *phys_kb = 0; *stored_kb = 0; *ratio = 0.0; return -1; } gint read_disk_swap (gulong *total_kb, gulong *used_kb) { *total_kb = 0; *used_kb = 0; return -1; } #endif /* __linux__ */