Files
Servers/MoonlightServers.Daemon/Helpers/SystemMetrics.Cpu.cs

76 lines
2.6 KiB
C#

namespace MoonlightServers.Daemon.Helpers;
public partial class SystemMetrics
{
public record CpuSnapshot(
string ModelName,
double TotalUsagePercent,
IReadOnlyList<double> CoreUsagePercents
);
private record RawCpuLine(
long User,
long Nice,
long System,
long Idle,
long Iowait,
long Irq,
long Softirq,
long Steal
);
private static async Task<List<RawCpuLine>> ReadRawCpuStatsAsync()
{
var lines = await File.ReadAllLinesAsync("/proc/stat");
var result = new List<RawCpuLine>();
foreach (var line in lines)
{
// All cpu* lines appear at the top of the file; stop on the first non-cpu line.
if (!line.StartsWith("cpu", StringComparison.Ordinal))
break;
var p = line.Split(' ', StringSplitOptions.RemoveEmptyEntries);
if (p.Length < 8)
continue;
result.Add(new RawCpuLine(
User: long.Parse(p[1]),
Nice: long.Parse(p[2]),
System: long.Parse(p[3]),
Idle: long.Parse(p[4]),
Iowait: long.Parse(p[5]),
Irq: long.Parse(p[6]),
Softirq: long.Parse(p[7]),
Steal: p.Length > 8 ? long.Parse(p[8]) : 0L
));
}
return result;
}
private static async Task<string> ReadCpuModelNameAsync()
{
var lines = await File.ReadAllLinesAsync("/proc/cpuinfo");
var line = lines.FirstOrDefault(l => l.StartsWith("model name", StringComparison.OrdinalIgnoreCase));
return line is not null ? line.Split(':')[1].Trim() : "Unknown";
}
private static CpuSnapshot ComputeCpuUsage(string modelName, List<RawCpuLine> s1, List<RawCpuLine> s2)
{
// Index 0 = aggregate "cpu" row; indices 1+ = "cpu0", "cpu1"
var totalUsage = s1.Count > 0 ? Usage(s1[0], s2[0]) : 0.0;
var coreUsages = s1.Skip(1).Zip(s2.Skip(1), Usage).ToList();
return new CpuSnapshot(modelName, totalUsage, coreUsages);
static double Usage(RawCpuLine a, RawCpuLine b)
{
var idleDelta = (b.Idle + b.Iowait) - (a.Idle + a.Iowait);
var totalDelta = (b.User + b.Nice + b.System + b.Idle + b.Iowait + b.Irq + b.Softirq + b.Steal)
- (a.User + a.Nice + a.System + a.Idle + a.Iowait + a.Irq + a.Softirq + a.Steal);
return totalDelta <= 0 ? 0.0 : Math.Round((1.0 - (double)idleDelta / totalDelta) * 100.0, 2);
}
}
}