186 lines
6.5 KiB
C#
186 lines
6.5 KiB
C#
using System.Diagnostics;
|
|
using System.Runtime.InteropServices;
|
|
#if WINDOWS
|
|
using System.Management; // NuGet: System.Management
|
|
using Microsoft.Win32;
|
|
#endif
|
|
|
|
namespace TWASys_App.Models.ServerInfo
|
|
{
|
|
public record SysInfo(int SocketCount, string? CpuName, ulong TotalRamBytes);
|
|
|
|
public static class SysInfoReader
|
|
{
|
|
public static SysInfo Get()
|
|
{
|
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
|
return GetWindows();
|
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
|
return GetLinux();
|
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
|
return GetMac();
|
|
return new SysInfo(0, null, 0);
|
|
}
|
|
|
|
// ---------- Windows ----------
|
|
static SysInfo GetWindows()
|
|
{
|
|
string? name = null;
|
|
int sockets = 0;
|
|
|
|
#if WINDOWS
|
|
// CPU name: registry
|
|
try
|
|
{
|
|
using var k = Registry.LocalMachine.OpenSubKey(
|
|
@"HARDWARE\DESCRIPTION\System\CentralProcessor\0");
|
|
name = k?.GetValue("ProcessorNameString")?.ToString()?.Trim();
|
|
} catch { }
|
|
|
|
// Sockets: mỗi Win32_Processor ~ 1 physical socket
|
|
try
|
|
{
|
|
using var s = new ManagementObjectSearcher(
|
|
"SELECT SocketDesignation FROM Win32_Processor");
|
|
foreach (ManagementObject _ in s.Get()) sockets++;
|
|
}
|
|
catch
|
|
{
|
|
// Fallback
|
|
try
|
|
{
|
|
using var s2 = new ManagementObjectSearcher(
|
|
"SELECT NumberOfProcessors FROM Win32_ComputerSystem");
|
|
foreach (ManagementObject mo in s2.Get())
|
|
sockets = Convert.ToInt32(mo["NumberOfProcessors"]);
|
|
} catch { }
|
|
}
|
|
#endif
|
|
// RAM: GlobalMemoryStatusEx
|
|
ulong total = GetTotalRamWindows();
|
|
return new SysInfo(sockets, name, total);
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
|
struct MEMORYSTATUSEX
|
|
{
|
|
public uint dwLength;
|
|
public uint dwMemoryLoad;
|
|
public ulong ullTotalPhys;
|
|
public ulong ullAvailPhys;
|
|
public ulong ullTotalPageFile;
|
|
public ulong ullAvailPageFile;
|
|
public ulong ullTotalVirtual;
|
|
public ulong ullAvailVirtual;
|
|
public ulong ullAvailExtendedVirtual;
|
|
}
|
|
|
|
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
|
static extern bool GlobalMemoryStatusEx(ref MEMORYSTATUSEX lpBuffer);
|
|
|
|
static ulong GetTotalRamWindows()
|
|
{
|
|
var st = new MEMORYSTATUSEX { dwLength = (uint)Marshal.SizeOf<MEMORYSTATUSEX>() };
|
|
return GlobalMemoryStatusEx(ref st) ? st.ullTotalPhys : 0UL;
|
|
}
|
|
|
|
// ---------- Linux ----------
|
|
static SysInfo GetLinux()
|
|
{
|
|
// CPU name
|
|
string? name = null;
|
|
try
|
|
{
|
|
foreach (var line in File.ReadLines("/proc/cpuinfo"))
|
|
if (line.StartsWith("model name", StringComparison.OrdinalIgnoreCase))
|
|
{ name = line[(line.IndexOf(':') + 1)..].Trim(); break; }
|
|
}
|
|
catch { }
|
|
if (string.IsNullOrWhiteSpace(name))
|
|
name = Run("bash", "-lc \"lscpu | grep -i 'Model name' | cut -d: -f2- | xargs\"");
|
|
|
|
// Socket count
|
|
int sockets = 0;
|
|
try
|
|
{
|
|
var set = new HashSet<string>(StringComparer.Ordinal);
|
|
foreach (var dir in Directory.GetDirectories("/sys/devices/system/cpu", "cpu*"))
|
|
{
|
|
var dn = Path.GetFileName(dir);
|
|
if (!dn.StartsWith("cpu") || !int.TryParse(dn[3..], out _)) continue;
|
|
var p = Path.Combine(dir, "topology", "physical_package_id");
|
|
if (File.Exists(p)) { var v = File.ReadAllText(p).Trim(); if (v != "") set.Add(v); }
|
|
}
|
|
sockets = set.Count;
|
|
}
|
|
catch { }
|
|
if (sockets == 0)
|
|
{
|
|
var s = Run("bash", "-lc \"lscpu | grep -i 'Socket(s)' | awk -F: '{print $2}' | xargs\"");
|
|
int.TryParse(s, out sockets);
|
|
}
|
|
|
|
// Total RAM: /proc/meminfo (MemTotal: kB)
|
|
ulong total = 0;
|
|
try
|
|
{
|
|
foreach (var line in File.ReadLines("/proc/meminfo"))
|
|
{
|
|
if (line.StartsWith("MemTotal:", StringComparison.Ordinal))
|
|
{
|
|
var parts = line.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
|
|
// ví dụ: "MemTotal: 16367472 kB"
|
|
if (parts.Length >= 2 && ulong.TryParse(parts[1], out var kb))
|
|
total = kb * 1024UL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
catch { }
|
|
if (total == 0)
|
|
{
|
|
var s = Run("bash", "-lc \"free -b | awk '/^Mem:/ {print $2}'\"");
|
|
ulong.TryParse(s, out total);
|
|
}
|
|
|
|
return new SysInfo(sockets, string.IsNullOrWhiteSpace(name) ? null : name, total);
|
|
}
|
|
|
|
// ---------- macOS ----------
|
|
static SysInfo GetMac()
|
|
{
|
|
var name = Run("sysctl", "-n machdep.cpu.brand_string");
|
|
var sSockets = Run("sysctl", "-n hw.packages"); // số package
|
|
int.TryParse(sSockets, out var sockets);
|
|
|
|
var mem = Run("sysctl", "-n hw.memsize");
|
|
ulong.TryParse(mem, out var total);
|
|
return new SysInfo(sockets, string.IsNullOrWhiteSpace(name) ? null : name.Trim(), total);
|
|
}
|
|
|
|
static string Run(string file, string args)
|
|
{
|
|
try
|
|
{
|
|
var p = new Process
|
|
{
|
|
StartInfo = new ProcessStartInfo
|
|
{
|
|
FileName = file,
|
|
Arguments = args,
|
|
RedirectStandardOutput = true,
|
|
RedirectStandardError = true,
|
|
UseShellExecute = false,
|
|
CreateNoWindow = true
|
|
}
|
|
};
|
|
p.Start();
|
|
var txt = p.StandardOutput.ReadToEnd();
|
|
p.WaitForExit(2000);
|
|
return txt.Trim();
|
|
}
|
|
catch { return ""; }
|
|
}
|
|
}
|
|
}
|