forked from MeloNX/MeloNX
* Fixed formatting/parsing issues with ApplicationData properties TimePlayed, LastPlayed, and FileSize Replaced double-based TimePlayed property with TimeSpan?-based one in ApplicationData and ApplicationMetadata Added a migration for TimePlayed, just like in #4861 Consolidated ApplicationData's FileSize* properties into one FileSize property Added a formatting/parsing helper class ValueFormatUtils for TimeSpans, DateTimes, and file sizes Added new value converters for TimeSpans and file sizes for the Avalonia UI Added TimePlayedSortComparer Fixed sort order in LastPlayedSortComparer Fixed sort order for ApplicationData fields TimePlayed, LastPlayed, and FileSize Fixed crashes caused by SortHelper Replaced SystemInfo.ToMiBString with ToGiBString backed by ValueFormatUtils Replaced SaveModel.GetSizeString() with ValueFormatUtils * Additional ApplicationLibrary changes that got lost in the last commit * Removed unneeded usings * Removed converters as they are no longer needed * Updated comment on FormatDateTime * Removed base10 parameter from ValueFormatUtils FormatFileSize now always returns base 2 values with base 10 units Made ParseFileSize capable of parsing both base 2 and base 10 units * Removed nullable attribute from TimePlayed property Centralized TimePlayed update code into ApplicationMetadata * Changed UpdateTimePlayed() to use TimeSpan logic * Removed JsonIgnore attributes from ApplicationData * Implemented requested format changes * Fixed mistakes in method documentation comments * Made it so the Last Played value "Never" is localized in the Avalonia UI * Implemented suggestions * Remove unused import * Did a comment refinement pass in ValueFormatUtils.cs * Reordered ValueFormatUtils methods and sorted them into #regions * Integrated functionality from #5056 Also removed Logger print from last_played migration code * Implemented suggestions * Moved ValueFormatUtils and SystemInfo to namespace Ryujinx.Ui.Common * common: Respect proper value format convention and use base10 by default This could be discuss again in another issue/PR, for now revert to the previous behavior. Signed-off-by: Mary Guillemard <mary@mary.zone> --------- Signed-off-by: Mary Guillemard <mary@mary.zone> Co-authored-by: TSR Berry <20988865+TSRBerry@users.noreply.github.com> Co-authored-by: Mary Guillemard <mary@mary.zone>
165 lines
5.3 KiB
C#
165 lines
5.3 KiB
C#
using Ryujinx.Common.Logging;
|
|
using System;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Runtime.InteropServices;
|
|
using System.Runtime.Versioning;
|
|
using System.Text;
|
|
|
|
namespace Ryujinx.Ui.Common.SystemInfo
|
|
{
|
|
[SupportedOSPlatform("macos")]
|
|
partial class MacOSSystemInfo : SystemInfo
|
|
{
|
|
internal MacOSSystemInfo()
|
|
{
|
|
if (SysctlByName("kern.osversion", out string buildRevision) != 0)
|
|
{
|
|
buildRevision = "Unknown Build";
|
|
}
|
|
|
|
OsDescription = $"macOS {Environment.OSVersion.Version} ({buildRevision}) ({RuntimeInformation.OSArchitecture})";
|
|
|
|
string cpuName = GetCpuidCpuName();
|
|
|
|
if (cpuName == null && SysctlByName("machdep.cpu.brand_string", out cpuName) != 0)
|
|
{
|
|
cpuName = "Unknown";
|
|
}
|
|
|
|
ulong totalRAM = 0;
|
|
|
|
if (SysctlByName("hw.memsize", ref totalRAM) != 0) // Bytes
|
|
{
|
|
totalRAM = 0;
|
|
}
|
|
|
|
CpuName = $"{cpuName} ; {LogicalCoreCount} logical";
|
|
RamTotal = totalRAM;
|
|
RamAvailable = GetVMInfoAvailableMemory();
|
|
}
|
|
|
|
static ulong GetVMInfoAvailableMemory()
|
|
{
|
|
var port = mach_host_self();
|
|
|
|
uint pageSize = 0;
|
|
var result = host_page_size(port, ref pageSize);
|
|
|
|
if (result != 0)
|
|
{
|
|
Logger.Error?.Print(LogClass.Application, $"Failed to query Available RAM. host_page_size() error = {result}");
|
|
return 0;
|
|
}
|
|
|
|
const int Flavor = 4; // HOST_VM_INFO64
|
|
uint count = (uint)(Marshal.SizeOf<VMStatistics64>() / sizeof(int)); // HOST_VM_INFO64_COUNT
|
|
VMStatistics64 stats = new();
|
|
result = host_statistics64(port, Flavor, ref stats, ref count);
|
|
|
|
if (result != 0)
|
|
{
|
|
Logger.Error?.Print(LogClass.Application, $"Failed to query Available RAM. host_statistics64() error = {result}");
|
|
return 0;
|
|
}
|
|
|
|
return (ulong)(stats.FreeCount + stats.InactiveCount) * pageSize;
|
|
}
|
|
|
|
private const string SystemLibraryName = "libSystem.dylib";
|
|
|
|
[LibraryImport(SystemLibraryName, SetLastError = true)]
|
|
private static partial int sysctlbyname([MarshalAs(UnmanagedType.LPStr)] string name, IntPtr oldValue, ref ulong oldSize, IntPtr newValue, ulong newValueSize);
|
|
|
|
private static int SysctlByName(string name, IntPtr oldValue, ref ulong oldSize)
|
|
{
|
|
if (sysctlbyname(name, oldValue, ref oldSize, IntPtr.Zero, 0) == -1)
|
|
{
|
|
int err = Marshal.GetLastWin32Error();
|
|
|
|
Logger.Error?.Print(LogClass.Application, $"Cannot retrieve '{name}'. Error Code {err}");
|
|
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
private static int SysctlByName<T>(string name, ref T oldValue)
|
|
{
|
|
unsafe
|
|
{
|
|
ulong oldValueSize = (ulong)Unsafe.SizeOf<T>();
|
|
|
|
return SysctlByName(name, (IntPtr)Unsafe.AsPointer(ref oldValue), ref oldValueSize);
|
|
}
|
|
}
|
|
|
|
private static int SysctlByName(string name, out string oldValue)
|
|
{
|
|
oldValue = default;
|
|
|
|
ulong strSize = 0;
|
|
|
|
int res = SysctlByName(name, IntPtr.Zero, ref strSize);
|
|
|
|
if (res == 0)
|
|
{
|
|
byte[] rawData = new byte[strSize];
|
|
|
|
unsafe
|
|
{
|
|
fixed (byte* rawDataPtr = rawData)
|
|
{
|
|
res = SysctlByName(name, (IntPtr)rawDataPtr, ref strSize);
|
|
}
|
|
|
|
if (res == 0)
|
|
{
|
|
oldValue = Encoding.ASCII.GetString(rawData);
|
|
}
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
[LibraryImport(SystemLibraryName, SetLastError = true)]
|
|
private static partial uint mach_host_self();
|
|
|
|
[LibraryImport(SystemLibraryName, SetLastError = true)]
|
|
private static partial int host_page_size(uint host, ref uint out_page_size);
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 8)]
|
|
struct VMStatistics64
|
|
{
|
|
public uint FreeCount;
|
|
public uint ActiveCount;
|
|
public uint InactiveCount;
|
|
public uint WireCount;
|
|
public ulong ZeroFillCount;
|
|
public ulong Reactivations;
|
|
public ulong Pageins;
|
|
public ulong Pageouts;
|
|
public ulong Faults;
|
|
public ulong CowFaults;
|
|
public ulong Lookups;
|
|
public ulong Hits;
|
|
public ulong Purges;
|
|
public uint PurgeableCount;
|
|
public uint SpeculativeCount;
|
|
public ulong Decompressions;
|
|
public ulong Compressions;
|
|
public ulong Swapins;
|
|
public ulong Swapouts;
|
|
public uint CompressorPageCount;
|
|
public uint ThrottledCount;
|
|
public uint ExternalPageCount;
|
|
public uint InternalPageCount;
|
|
public ulong TotalUncompressedPagesInCompressor;
|
|
}
|
|
|
|
[LibraryImport(SystemLibraryName, SetLastError = true)]
|
|
private static partial int host_statistics64(uint hostPriv, int hostFlavor, ref VMStatistics64 hostInfo64Out, ref uint hostInfo64OutCnt);
|
|
}
|
|
}
|