namespace MoonlightServers.Daemon.Helpers;
public partial class SystemMetrics
{
/// Memory figures derived from /proc/meminfo.
/// Physical RAM installed.
/// RAM actively in use (Total - Available).
/// Completely unallocated RAM.
/// Page cache + reclaimable slab — matches the cached column in free -h.
/// Kernel I/O buffer memory.
/// Estimated RAM available for new allocations without swapping.
/// UsedBytes / TotalBytes as a percentage (0–100).
public record MemoryInfo(
long TotalBytes,
long UsedBytes,
long FreeBytes,
long CachedBytes,
long BuffersBytes,
long AvailableBytes,
double UsedPercent
);
// Memory — /proc/meminfo
///
/// Parses /proc/meminfo into a record.
/// The CachedBytes field is computed as
/// Cached + SReclaimable - Shmem to match the value shown by free -h.
///
private static async Task ReadMemoryAsync()
{
var lines = await File.ReadAllLinesAsync("/proc/meminfo");
var map = new Dictionary(StringComparer.Ordinal);
foreach (var line in lines)
{
var colon = line.IndexOf(':');
if (colon < 0)
continue;
var key = line[..colon].Trim();
var val = line[(colon + 1)..].Trim().Split(' ')[0]; // Strip "kB" suffix.
if (long.TryParse(val, out var kb))
map[key] = kb * 1024L;
}
var total = map.GetValueOrDefault("MemTotal");
var available = map.GetValueOrDefault("MemAvailable");
var free = map.GetValueOrDefault("MemFree");
var buffers = map.GetValueOrDefault("Buffers");
var cached = map.GetValueOrDefault("Cached")
+ map.GetValueOrDefault("SReclaimable")
- map.GetValueOrDefault("Shmem");
var used = total - available;
var usedPct = total > 0 ? Math.Round((double)used / total * 100.0, 2) : 0.0;
return new MemoryInfo(total, used, free, cached, buffers, available, usedPct);
}
}