forked from amkovkov/GranuSightSoftware2
feat: GSS2.Test refactor + ComputeResourcesService
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user