xfce4-systemload-plugin-zram/panel-plugin/zram.cc

226 lines
5.3 KiB
C++
Raw Normal View History

/*
* 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 <config.h>
#endif
#include <glib.h>
#include <glib/gstdio.h>
#include "zram.h"
#ifdef __linux__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* /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__ */