MacOSSystemInfo.cs
1 using Ryujinx.Common.Logging; 2 using System; 3 using System.Runtime.CompilerServices; 4 using System.Runtime.InteropServices; 5 using System.Runtime.Versioning; 6 using System.Text; 7 8 namespace Ryujinx.UI.Common.SystemInfo 9 { 10 [SupportedOSPlatform("macos")] 11 partial class MacOSSystemInfo : SystemInfo 12 { 13 internal MacOSSystemInfo() 14 { 15 if (SysctlByName("kern.osversion", out string buildRevision) != 0) 16 { 17 buildRevision = "Unknown Build"; 18 } 19 20 OsDescription = $"macOS {Environment.OSVersion.Version} ({buildRevision}) ({RuntimeInformation.OSArchitecture})"; 21 22 string cpuName = GetCpuidCpuName(); 23 24 if (cpuName == null && SysctlByName("machdep.cpu.brand_string", out cpuName) != 0) 25 { 26 cpuName = "Unknown"; 27 } 28 29 ulong totalRAM = 0; 30 31 if (SysctlByName("hw.memsize", ref totalRAM) != 0) // Bytes 32 { 33 totalRAM = 0; 34 } 35 36 CpuName = $"{cpuName} ; {LogicalCoreCount} logical"; 37 RamTotal = totalRAM; 38 RamAvailable = GetVMInfoAvailableMemory(); 39 } 40 41 static ulong GetVMInfoAvailableMemory() 42 { 43 var port = mach_host_self(); 44 45 uint pageSize = 0; 46 var result = host_page_size(port, ref pageSize); 47 48 if (result != 0) 49 { 50 Logger.Error?.Print(LogClass.Application, $"Failed to query Available RAM. host_page_size() error = {result}"); 51 return 0; 52 } 53 54 const int Flavor = 4; // HOST_VM_INFO64 55 uint count = (uint)(Marshal.SizeOf<VMStatistics64>() / sizeof(int)); // HOST_VM_INFO64_COUNT 56 VMStatistics64 stats = new(); 57 result = host_statistics64(port, Flavor, ref stats, ref count); 58 59 if (result != 0) 60 { 61 Logger.Error?.Print(LogClass.Application, $"Failed to query Available RAM. host_statistics64() error = {result}"); 62 return 0; 63 } 64 65 return (ulong)(stats.FreeCount + stats.InactiveCount) * pageSize; 66 } 67 68 private const string SystemLibraryName = "libSystem.dylib"; 69 70 [LibraryImport(SystemLibraryName, SetLastError = true)] 71 private static partial int sysctlbyname([MarshalAs(UnmanagedType.LPStr)] string name, IntPtr oldValue, ref ulong oldSize, IntPtr newValue, ulong newValueSize); 72 73 private static int SysctlByName(string name, IntPtr oldValue, ref ulong oldSize) 74 { 75 if (sysctlbyname(name, oldValue, ref oldSize, IntPtr.Zero, 0) == -1) 76 { 77 int err = Marshal.GetLastWin32Error(); 78 79 Logger.Error?.Print(LogClass.Application, $"Cannot retrieve '{name}'. Error Code {err}"); 80 81 return err; 82 } 83 84 return 0; 85 } 86 87 private static int SysctlByName<T>(string name, ref T oldValue) 88 { 89 unsafe 90 { 91 ulong oldValueSize = (ulong)Unsafe.SizeOf<T>(); 92 93 return SysctlByName(name, (IntPtr)Unsafe.AsPointer(ref oldValue), ref oldValueSize); 94 } 95 } 96 97 private static int SysctlByName(string name, out string oldValue) 98 { 99 oldValue = default; 100 101 ulong strSize = 0; 102 103 int res = SysctlByName(name, IntPtr.Zero, ref strSize); 104 105 if (res == 0) 106 { 107 byte[] rawData = new byte[strSize]; 108 109 unsafe 110 { 111 fixed (byte* rawDataPtr = rawData) 112 { 113 res = SysctlByName(name, (IntPtr)rawDataPtr, ref strSize); 114 } 115 116 if (res == 0) 117 { 118 oldValue = Encoding.ASCII.GetString(rawData); 119 } 120 } 121 } 122 123 return res; 124 } 125 126 [LibraryImport(SystemLibraryName, SetLastError = true)] 127 private static partial uint mach_host_self(); 128 129 [LibraryImport(SystemLibraryName, SetLastError = true)] 130 private static partial int host_page_size(uint host, ref uint out_page_size); 131 132 [StructLayout(LayoutKind.Sequential, Pack = 8)] 133 struct VMStatistics64 134 { 135 public uint FreeCount; 136 public uint ActiveCount; 137 public uint InactiveCount; 138 public uint WireCount; 139 public ulong ZeroFillCount; 140 public ulong Reactivations; 141 public ulong Pageins; 142 public ulong Pageouts; 143 public ulong Faults; 144 public ulong CowFaults; 145 public ulong Lookups; 146 public ulong Hits; 147 public ulong Purges; 148 public uint PurgeableCount; 149 public uint SpeculativeCount; 150 public ulong Decompressions; 151 public ulong Compressions; 152 public ulong Swapins; 153 public ulong Swapouts; 154 public uint CompressorPageCount; 155 public uint ThrottledCount; 156 public uint ExternalPageCount; 157 public uint InternalPageCount; 158 public ulong TotalUncompressedPagesInCompressor; 159 } 160 161 [LibraryImport(SystemLibraryName, SetLastError = true)] 162 private static partial int host_statistics64(uint hostPriv, int hostFlavor, ref VMStatistics64 hostInfo64Out, ref uint hostInfo64OutCnt); 163 } 164 }