- zram.cc/.h: read zram usage; memory bar can subtract RAM held by zram
- memswap: zram and disk swap shown separately in the tooltip
- uptime: format string with %d %h %m %s, %H %M %S, %t, \n and {...}
- settings dialog fields for both, Russian translation
- tests/test_format_uptime.cc with tests/run.sh
This is what the installed 1:1.3.2-2ubuntu3+zram2 package was built from.
226 lines
5.3 KiB
C++
226 lines
5.3 KiB
C++
/*
|
|
* 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__ */
|