feat: GSS2.Test refactor + ComputeResourcesService

This commit is contained in:
2026-01-26 13:54:29 +03:00
parent d4e7c300f4
commit 58f307c444
25 changed files with 798 additions and 87 deletions
@@ -0,0 +1,141 @@
using System.Globalization;
using GSS2.Core.Extentions;
using Microsoft.Extensions.Logging;
namespace GSS2.Core.Hardware;
public class ComputeResourcesService
{
public record CpuUsage(double AllUsagePercent, List<double> CoreUsagePercents);
public record CpuTemperature(double Current, double Critical);
public record MemoryUsage(
long TotalB, long UsedB, long AvailableB,
double TotalkB, double UsedkB, double AvailablekB,
double TotalMB, double UsedMB, double AvailableMB,
double TotalGB, double UsedGB, double AvailableGB)
{
public MemoryUsage(long totalB, long usedB, long availableB) :
this(
TotalB: totalB, UsedB: usedB, AvailableB: availableB,
TotalkB: totalB / 1000, UsedkB: usedB / 1000, AvailablekB: availableB / 1000,
TotalMB: totalB / Math.Pow(1000.0, 2), UsedMB: usedB / Math.Pow(1000.0, 2), AvailableMB: availableB / Math.Pow(1000.0, 2),
TotalGB: totalB / Math.Pow(1000.0, 3), UsedGB: usedB / Math.Pow(1000.0, 3), AvailableGB: availableB / Math.Pow(1000.0, 3)
)
{ }
}
public record ComputeResourcesSnapshot(CpuUsage CpuUsage, MemoryUsage MemoryUsage, CpuTemperature CpuTemperature, DateTime Timestamp);
private readonly ILogger<ComputeResourcesService> _logger;
private (long idle, long total)? _prevAll = null;
private Dictionary<int, (long idle, long total)?>? _prevCores = null;
public ComputeResourcesService(ILogger<ComputeResourcesService> logger)
{
_logger = logger;
}
public ComputeResourcesSnapshot GetSnapshot()
{
return new ComputeResourcesSnapshot(
CpuUsage: GetCpuUsage(),
CpuTemperature: GetCpuTemperature(),
MemoryUsage: GetMemoryUsage(),
Timestamp: DateTime.UtcNow
);
}
private CpuUsage GetCpuUsage()
{
static (double usage, long idle, long total) ParceLines(string line, (long idle, long total)? prev)
{
var parts = line.Split(' ', StringSplitOptions.RemoveEmptyEntries);
long user = long.Parse(parts[1]);
long nice = long.Parse(parts[2]);
long system = long.Parse(parts[3]);
long idle = long.Parse(parts[4]);
long iowait = line.Length > 5 ? long.Parse(parts[5]) : 0;
long irq = line.Length > 6 ? long.Parse(parts[6]) : 0;
long softirq = line.Length > 7 ? long.Parse(parts[7]) : 0;
long idleTime = idle + iowait;
long totalTime = idleTime + user + nice + system + irq + softirq;
double usage = 0;
if (prev is not null)
{
long totalDiff = totalTime - prev.Value.total;
long idleDiff = idleTime - prev.Value.idle;
if (totalDiff > 0)
usage = (double)(totalDiff - idleDiff) / totalDiff * 100.0;
}
return (usage, idleTime, totalTime);
}
var lines = File.ReadLines("/proc/stat").Where(l => l.StartsWith("cpu"));
if (lines.Count() == 0)
return new CpuUsage(0, new List<double>());
var (allUsage, allIdle, allTotal) = ParceLines(lines.First(), _prevAll);
_prevAll = (allIdle, allTotal);
var coreUsages = new List<double>();
foreach (var (i, line) in lines.Skip(1).Enumerate())
{
if (_prevCores is null)
_prevCores = new Dictionary<int, (long idle, long total)?>();
if (!_prevCores.ContainsKey(i))
_prevCores.Add(i, null);
var (coreUsage, coreIdle, coreTotal) = ParceLines(line, _prevCores[i]);
_prevCores[i] = (coreIdle, coreTotal);
coreUsages.Add(coreUsage);
}
return new CpuUsage(
AllUsagePercent: allUsage,
CoreUsagePercents: coreUsages
);
}
private CpuTemperature GetCpuTemperature()
{
var currentStr = File.ReadAllText("/sys/class/thermal/thermal_zone0/temp").Trim();
var current = int.Parse(currentStr) / 1000.0;
var criticalFile = Directory.GetFiles("/sys/class/thermal/thermal_zone0/", "trip_point_*_type")
.FirstOrDefault(f => File.ReadAllText(f).Trim() == "critical")?
.Replace("_type", "_temp");
double critical = 100.0;
if (criticalFile is not null)
{
var criticalStr = File.ReadAllText(criticalFile).Trim();
critical = int.Parse(criticalStr) / 1000.0;
}
return new CpuTemperature(
Current: current,
Critical: critical
);
}
private MemoryUsage GetMemoryUsage()
{
var memInfo = File.ReadAllLines("/proc/meminfo")
.Select(l => l.Split(':', 2))
.ToDictionary(
p => p[0],
p => long.Parse(p[1].Trim().Split(' ')[0], CultureInfo.InvariantCulture) * 1024
);
long total = memInfo["MemTotal"];
long available = memInfo.ContainsKey("MemAvailable") ? memInfo["MemAvailable"] : memInfo["MemFree"];
long used = total - available;
return new MemoryUsage(totalB: total, usedB: used, availableB: available);
}
}