diff --git a/LibreHardwareMonitor/UI/MainForm.cs b/LibreHardwareMonitor/UI/MainForm.cs index 474ba4d..a252246 100644 --- a/LibreHardwareMonitor/UI/MainForm.cs +++ b/LibreHardwareMonitor/UI/MainForm.cs @@ -122,9 +122,9 @@ namespace LibreHardwareMonitor.UI _systemTray.HideShowCommand += HideShowClick; _systemTray.ExitCommand += ExitClick; - int p = (int)Environment.OSVersion.Platform; - if ((p == 4) || (p == 128)) - { // Unix + if (Software.OperatingSystem.IsUnix) + { + // Unix treeView.RowHeight = Math.Max(treeView.RowHeight, 18); splitContainer.BorderStyle = BorderStyle.None; splitContainer.Border3DStyle = Border3DStyle.Adjust; diff --git a/LibreHardwareMonitorLib/Hardware/Controller/Heatmaster/HeatmasterGroup.cs b/LibreHardwareMonitorLib/Hardware/Controller/Heatmaster/HeatmasterGroup.cs index 267ea4b..2de26a4 100644 --- a/LibreHardwareMonitorLib/Hardware/Controller/Heatmaster/HeatmasterGroup.cs +++ b/LibreHardwareMonitorLib/Hardware/Controller/Heatmaster/HeatmasterGroup.cs @@ -23,7 +23,7 @@ namespace LibreHardwareMonitor.Hardware.Controller.Heatmaster public HeatmasterGroup(ISettings settings) { // No implementation for Heatmaster on Unix systems - if (Software.OperatingSystem.IsLinux) + if (Software.OperatingSystem.IsUnix) return; diff --git a/LibreHardwareMonitorLib/Hardware/Cpu/Amd0FCpu.cs b/LibreHardwareMonitorLib/Hardware/Cpu/Amd0FCpu.cs index b5a50a2..7eb67c4 100644 --- a/LibreHardwareMonitorLib/Hardware/Cpu/Amd0FCpu.cs +++ b/LibreHardwareMonitorLib/Hardware/Cpu/Amd0FCpu.cs @@ -120,7 +120,7 @@ namespace LibreHardwareMonitor.Hardware.CPU { Thread.Sleep(1); - if (Ring0.ReadMsr(FIDVID_STATUS, out uint eax, out uint _, 1UL << _cpuId[i][0].Thread)) + if (Ring0.ReadMsr(FIDVID_STATUS, out uint eax, out uint _, _cpuId[i][0].Affinity)) { // CurrFID can be found in eax bits 0-5, MaxFID in 16-21 // 8-13 hold StartFID, we don't use that here. diff --git a/LibreHardwareMonitorLib/Hardware/Cpu/Amd10Cpu.cs b/LibreHardwareMonitorLib/Hardware/Cpu/Amd10Cpu.cs index 62fe6e7..c82495d 100644 --- a/LibreHardwareMonitorLib/Hardware/Cpu/Amd10Cpu.cs +++ b/LibreHardwareMonitorLib/Hardware/Cpu/Amd10Cpu.cs @@ -143,7 +143,7 @@ namespace LibreHardwareMonitor.Hardware.CPU bool corePerformanceBoostSupport = (cpuId[0][0].ExtData[7, 3] & (1 << 9)) > 0; // set affinity to the first thread for all frequency estimations - ulong mask = ThreadAffinity.Set(1UL << cpuId[0][0].Thread); + var previousAffinity = ThreadAffinity.Set(cpuId[0][0].Affinity); // disable core performance boost Ring0.ReadMsr(HWCR, out uint hwcrEax, out uint hwcrEdx); @@ -164,12 +164,12 @@ namespace LibreHardwareMonitor.Hardware.CPU Ring0.WriteMsr(HWCR, hwcrEax, hwcrEdx); // restore the thread affinity. - ThreadAffinity.Set(mask); + ThreadAffinity.Set(previousAffinity); // the file reader for lm-sensors support on Linux _temperatureStream = null; - if (Software.OperatingSystem.IsLinux) + if (Software.OperatingSystem.IsUnix) { string[] devicePaths = Directory.GetDirectories("/sys/class/hwmon/"); foreach (string path in devicePaths) @@ -177,8 +177,9 @@ namespace LibreHardwareMonitor.Hardware.CPU string name = null; try { - using (StreamReader reader = new StreamReader(path + "/device/name")) - name = reader.ReadLine(); + using StreamReader reader = new StreamReader(path + "/device/name"); + + name = reader.ReadLine(); } catch (IOException) { } @@ -450,7 +451,7 @@ namespace LibreHardwareMonitor.Hardware.CPU { Thread.Sleep(1); - if (Ring0.ReadMsr(COFVID_STATUS, out uint curEax, out uint _, 1UL << _cpuId[i][0].Thread)) + if (Ring0.ReadMsr(COFVID_STATUS, out uint curEax, out uint _, _cpuId[i][0].Affinity)) { double multiplier = GetCoreMultiplier(curEax); diff --git a/LibreHardwareMonitorLib/Hardware/Cpu/Amd17Cpu.cs b/LibreHardwareMonitorLib/Hardware/Cpu/Amd17Cpu.cs index eee0c37..de3d6f1 100644 --- a/LibreHardwareMonitorLib/Hardware/Cpu/Amd17Cpu.cs +++ b/LibreHardwareMonitorLib/Hardware/Cpu/Amd17Cpu.cs @@ -96,7 +96,7 @@ namespace LibreHardwareMonitor.Hardware.CPU private readonly Sensor _coreTemperatureTctlTdie; private readonly Sensor[] _ccdTemperatures; private readonly Sensor _coreVoltage; - private readonly Amd17Cpu _hw; + private readonly Amd17Cpu _hardware; private readonly Sensor _packagePower; private readonly Sensor _socVoltage; private Sensor _ccdsMaxTemperature; @@ -104,20 +104,20 @@ namespace LibreHardwareMonitor.Hardware.CPU private DateTime _lastPwrTime = new DateTime(0); private uint _lastPwrValue; - public Processor(Hardware hw) + public Processor(Hardware hardware) { - _hw = (Amd17Cpu)hw; + _hardware = (Amd17Cpu)hardware; Nodes = new List(); - _packagePower = new Sensor("Package Power", _hw._sensorPower++, SensorType.Power, _hw, _hw._settings); - _coreTemperatureTctl = new Sensor("Core (Tctl)", _hw._sensorTemperatures++, SensorType.Temperature, _hw, _hw._settings); - _coreTemperatureTdie = new Sensor("Core (Tdie)", _hw._sensorTemperatures++, SensorType.Temperature, _hw, _hw._settings); - _coreTemperatureTctlTdie = new Sensor("Core (Tctl/Tdie)", _hw._sensorTemperatures++, SensorType.Temperature, _hw, _hw._settings); + _packagePower = new Sensor("Package Power", _hardware._sensorPower++, SensorType.Power, _hardware, _hardware._settings); + _coreTemperatureTctl = new Sensor("Core (Tctl)", _hardware._sensorTemperatures++, SensorType.Temperature, _hardware, _hardware._settings); + _coreTemperatureTdie = new Sensor("Core (Tdie)", _hardware._sensorTemperatures++, SensorType.Temperature, _hardware, _hardware._settings); + _coreTemperatureTctlTdie = new Sensor("Core (Tctl/Tdie)", _hardware._sensorTemperatures++, SensorType.Temperature, _hardware, _hardware._settings); _ccdTemperatures = new Sensor[8]; // Hardcoded until there's a way to get max CCDs. - _coreVoltage = new Sensor("Core (SVI2 TFN)", _hw._sensorVoltage++, SensorType.Voltage, _hw, _hw._settings); - _socVoltage = new Sensor("SoC (SVI2 TFN)", _hw._sensorVoltage++, SensorType.Voltage, _hw, _hw._settings); + _coreVoltage = new Sensor("Core (SVI2 TFN)", _hardware._sensorVoltage++, SensorType.Voltage, _hardware, _hardware._settings); + _socVoltage = new Sensor("SoC (SVI2 TFN)", _hardware._sensorVoltage++, SensorType.Voltage, _hardware, _hardware._settings); - _hw.ActivateSensor(_packagePower); + _hardware.ActivateSensor(_packagePower); } public List Nodes { get; } @@ -131,7 +131,7 @@ namespace LibreHardwareMonitor.Hardware.CPU return; - ulong mask = Ring0.ThreadAffinitySet(1UL << cpu.Thread); + GroupAffinity previousAffinity = ThreadAffinity.Set(cpu.Affinity); // MSRC001_0299 // TU [19:16] @@ -195,7 +195,7 @@ namespace LibreHardwareMonitor.Hardware.CPU Ring0.WritePciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER, sviPlane1Offset); Ring0.ReadPciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER + 4, out uint smuSvi0TelPlane1); - Ring0.ThreadAffinitySet(mask); + ThreadAffinity.Set(previousAffinity); // power consumption // power.Value = (float) ((double)pu * 0.125); @@ -250,14 +250,14 @@ namespace LibreHardwareMonitor.Hardware.CPU _coreTemperatureTctl.Value = t; _coreTemperatureTdie.Value = t + offset; - _hw.ActivateSensor(_coreTemperatureTctl); - _hw.ActivateSensor(_coreTemperatureTdie); + _hardware.ActivateSensor(_coreTemperatureTctl); + _hardware.ActivateSensor(_coreTemperatureTdie); } else { // Zen 2 doesn't have an offset so Tdie and Tctl are the same. _coreTemperatureTctlTdie.Value = t; - _hw.ActivateSensor(_coreTemperatureTctlTdie); + _hardware.ActivateSensor(_coreTemperatureTctlTdie); } // Tested only on R5 3600 & Threadripper 3960X. @@ -279,11 +279,11 @@ namespace LibreHardwareMonitor.Hardware.CPU if (_ccdTemperatures[i] == null) { - _hw.ActivateSensor(_ccdTemperatures[i] = new Sensor($"CCD{i + 1} (Tdie)", - _hw._sensorTemperatures++, + _hardware.ActivateSensor(_ccdTemperatures[i] = new Sensor($"CCD{i + 1} (Tdie)", + _hardware._sensorTemperatures++, SensorType.Temperature, - _hw, - _hw._settings)); + _hardware, + _hardware._settings)); } _ccdTemperatures[i].Value = ccdTemp; @@ -296,20 +296,20 @@ namespace LibreHardwareMonitor.Hardware.CPU if (_ccdsMaxTemperature == null) { - _hw.ActivateSensor(_ccdsMaxTemperature = new Sensor("CCDs Max (Tdie)", - _hw._sensorTemperatures++, + _hardware.ActivateSensor(_ccdsMaxTemperature = new Sensor("CCDs Max (Tdie)", + _hardware._sensorTemperatures++, SensorType.Temperature, - _hw, - _hw._settings)); + _hardware, + _hardware._settings)); } if (_ccdsAverageTemperature == null) { - _hw.ActivateSensor(_ccdsAverageTemperature = new Sensor("CCDs Average (Tdie)", - _hw._sensorTemperatures++, + _hardware.ActivateSensor(_ccdsAverageTemperature = new Sensor("CCDs Average (Tdie)", + _hardware._sensorTemperatures++, SensorType.Temperature, - _hw, - _hw._settings)); + _hardware, + _hardware._settings)); } _ccdsMaxTemperature.Value = activeCcds.Max(x => x.Value); @@ -329,7 +329,7 @@ namespace LibreHardwareMonitor.Hardware.CPU vcc = 1.550 - vidStep * svi0PlaneXVddCor; _coreVoltage.Value = (float)vcc; - _hw.ActivateSensor(_coreVoltage); + _hardware.ActivateSensor(_coreVoltage); } // SoC (0x02), not every Zen cpu has this voltage. @@ -339,7 +339,7 @@ namespace LibreHardwareMonitor.Hardware.CPU vcc = 1.550 - vidStep * svi0PlaneXVddCor; _socVoltage.Value = (float)vcc; - _hw.ActivateSensor(_socVoltage); + _hardware.ActivateSensor(_socVoltage); } } @@ -357,7 +357,7 @@ namespace LibreHardwareMonitor.Hardware.CPU if (node == null) { - node = new NumaNode(_hw, numaId); + node = new NumaNode(_hardware, numaId); Nodes.Add(node); } @@ -441,7 +441,7 @@ namespace LibreHardwareMonitor.Hardware.CPU return; - ulong mask = Ring0.ThreadAffinitySet(1UL << cpu.Thread); + var previousAffinity = ThreadAffinity.Set(cpu.Affinity); // MSRC001_0299 // TU [19:16] @@ -476,7 +476,7 @@ namespace LibreHardwareMonitor.Hardware.CPU // int IddDiv = (int)((eax >> 30) & 0x03); // int IddValue = (int)((eax >> 22) & 0xff); // int CpuVid = (int)((eax >> 14) & 0xff); - Ring0.ThreadAffinitySet(mask); + ThreadAffinity.Set(previousAffinity); // clock // CoreCOF is (Core::X86::Msr::PStateDef[CpuFid[7:0]] / Core::X86::Msr::PStateDef[CpuDfsId]) * 200 diff --git a/LibreHardwareMonitorLib/Hardware/Cpu/CpuGroup.cs b/LibreHardwareMonitorLib/Hardware/Cpu/CpuGroup.cs index e050613..858c8d8 100644 --- a/LibreHardwareMonitorLib/Hardware/Cpu/CpuGroup.cs +++ b/LibreHardwareMonitorLib/Hardware/Cpu/CpuGroup.cs @@ -96,6 +96,7 @@ namespace LibreHardwareMonitor.Hardware.CPU { for (int k = 0; k < _threads[i][j].Length; k++) { + r.AppendLine(" CPU Group: " + _threads[i][j][k].Group); r.AppendLine(" CPU Thread: " + _threads[i][j][k].Thread); r.AppendLine(" APIC ID: " + _threads[i][j][k].ApicId); r.AppendLine(" Processor ID: " + _threads[i][j][k].ProcessorId); @@ -124,19 +125,30 @@ namespace LibreHardwareMonitor.Hardware.CPU private static CpuId[][] GetProcessorThreads() { List threads = new List(); - for (int i = 0; i < 64; i++) + + for (int i = 0; i < ThreadAffinity.ProcessorGroupCount; i++) { - try + for (int j = 0; j < 64; j++) { - threads.Add(new CpuId(i)); - } - catch (ArgumentOutOfRangeException) - { - // All cores found. - break; + try + { + if (!ThreadAffinity.IsValid(GroupAffinity.Single((ushort)i, j))) + continue; + + + var cpuid = CpuId.Get(i, j); + if (cpuid != null) + threads.Add(cpuid); + } + catch (ArgumentOutOfRangeException) + { + // All cores found. + break; + } } } + SortedDictionary> processors = new SortedDictionary>(); foreach (CpuId thread in threads) { diff --git a/LibreHardwareMonitorLib/Hardware/Cpu/CpuId.cs b/LibreHardwareMonitorLib/Hardware/Cpu/CpuId.cs index e3c6038..dd6ce3e 100644 --- a/LibreHardwareMonitorLib/Hardware/Cpu/CpuId.cs +++ b/LibreHardwareMonitorLib/Hardware/Cpu/CpuId.cs @@ -18,25 +18,28 @@ namespace LibreHardwareMonitor.Hardware.CPU public class CpuId { - // ReSharper disable InconsistentNaming - public const uint CPUID_0 = 0; - public const uint CPUID_EXT = 0x80000000; - // ReSharper restore InconsistentNaming - - public CpuId(int thread) + /// + /// Initializes a new instance of the class. + /// + /// The group. + /// The thread. + /// The affinity. + private CpuId(int group, int thread, GroupAffinity affinity) { + Thread = thread; + Group = group; + Affinity = affinity; + uint threadMaskWith; uint coreMaskWith; - Thread = thread; uint maxCpuidExt; if (thread >= 64) throw new ArgumentOutOfRangeException(nameof(thread)); - ulong mask = 1UL << thread; uint maxCpuid; - if (OpCode.CpuidTx(CPUID_0, 0, out uint eax, out uint ebx, out uint ecx, out uint edx, mask)) + if (OpCode.CpuId(CPUID_0, 0, out uint eax, out uint ebx, out uint ecx, out uint edx)) { if (eax > 0) maxCpuid = eax; @@ -49,6 +52,7 @@ namespace LibreHardwareMonitor.Hardware.CPU AppendRegister(vendorBuilder, edx); AppendRegister(vendorBuilder, ecx); string cpuVendor = vendorBuilder.ToString(); + switch (cpuVendor) { case "GenuineIntel": @@ -62,7 +66,7 @@ namespace LibreHardwareMonitor.Hardware.CPU break; } - if (OpCode.CpuidTx(CPUID_EXT, 0, out eax, out _, out _, out _, mask)) + if (OpCode.CpuId(CPUID_EXT, 0, out eax, out _, out _, out _)) { if (eax > CPUID_EXT) maxCpuidExt = eax - CPUID_EXT; @@ -85,19 +89,19 @@ namespace LibreHardwareMonitor.Hardware.CPU Data = new uint[maxCpuid + 1, 4]; for (uint i = 0; i < maxCpuid + 1; i++) { - OpCode.CpuidTx(CPUID_0 + i, 0, out Data[i, 0], out Data[i, 1], out Data[i, 2], out Data[i, 3], mask); + OpCode.CpuId(CPUID_0 + i, 0, out Data[i, 0], out Data[i, 1], out Data[i, 2], out Data[i, 3]); } ExtData = new uint[maxCpuidExt + 1, 4]; for (uint i = 0; i < maxCpuidExt + 1; i++) { - OpCode.CpuidTx(CPUID_EXT + i, 0, out ExtData[i, 0], out ExtData[i, 1], out ExtData[i, 2], out ExtData[i, 3], mask); + OpCode.CpuId(CPUID_EXT + i, 0, out ExtData[i, 0], out ExtData[i, 1], out ExtData[i, 2], out ExtData[i, 3]); } StringBuilder nameBuilder = new StringBuilder(); for (uint i = 2; i <= 4; i++) { - if (OpCode.CpuidTx(CPUID_EXT + i, 0, out eax, out ebx, out ecx, out edx, mask)) + if (OpCode.CpuId(CPUID_EXT + i, 0, out eax, out ebx, out ecx, out edx)) { AppendRegister(nameBuilder, eax); AppendRegister(nameBuilder, ebx); @@ -141,6 +145,7 @@ namespace LibreHardwareMonitor.Hardware.CPU switch (Vendor) { case Vendor.Intel: + { uint maxCoreAndThreadIdPerPackage = (Data[1, 1] >> 16) & 0xFF; uint maxCoreIdPerPackage; if (maxCpuid >= 4) @@ -151,7 +156,9 @@ namespace LibreHardwareMonitor.Hardware.CPU threadMaskWith = NextLog2(maxCoreAndThreadIdPerPackage / maxCoreIdPerPackage); coreMaskWith = NextLog2(maxCoreIdPerPackage); break; + } case Vendor.AMD: + { uint corePerPackage; if (maxCpuidExt >= 8) corePerPackage = (ExtData[8, 2] & 0xFF) + 1; @@ -171,22 +178,31 @@ namespace LibreHardwareMonitor.Hardware.CPU switch (maxCoresPerDie) { case 0x04: // Ryzen + { coreMaskWith = NextLog2(16); break; + } case 0x05: // Threadripper + { coreMaskWith = NextLog2(32); break; + } case 0x06: // Epic + { coreMaskWith = NextLog2(64); break; + } } } break; + } default: + { threadMaskWith = 0; coreMaskWith = 0; break; + } } ProcessorId = ApicId >> (int)(coreMaskWith + threadMaskWith); @@ -194,6 +210,8 @@ namespace LibreHardwareMonitor.Hardware.CPU ThreadId = ApicId - (ProcessorId << (int)(coreMaskWith + threadMaskWith)) - (CoreId << (int)threadMaskWith); } + public GroupAffinity Affinity { get; } + public uint ApicId { get; } public string BrandString { get; } = string.Empty; @@ -206,6 +224,8 @@ namespace LibreHardwareMonitor.Hardware.CPU public uint Family { get; } + public int Group { get; } + public uint Model { get; } public string Name { get; } = string.Empty; @@ -220,6 +240,35 @@ namespace LibreHardwareMonitor.Hardware.CPU public Vendor Vendor { get; } = Vendor.Unknown; + /// + /// Gets the specified . + /// + /// The group. + /// The thread. + /// . + public static CpuId Get(int group, int thread) + { + if (thread >= 64) + return null; + + + var affinity = GroupAffinity.Single((ushort)group, thread); + + GroupAffinity previousAffinity = ThreadAffinity.Set(affinity); + if (previousAffinity == GroupAffinity.Undefined) + return null; + + + try + { + return new CpuId(group, thread, affinity); + } + finally + { + ThreadAffinity.Set(previousAffinity); + } + } + private static void AppendRegister(StringBuilder b, uint value) { b.Append((char)(value & 0xff)); @@ -244,5 +293,10 @@ namespace LibreHardwareMonitor.Hardware.CPU return count; } + + // ReSharper disable InconsistentNaming + public const uint CPUID_0 = 0; + public const uint CPUID_EXT = 0x80000000; + // ReSharper restore InconsistentNaming } } diff --git a/LibreHardwareMonitorLib/Hardware/Cpu/GenericCpu.cs b/LibreHardwareMonitorLib/Hardware/Cpu/GenericCpu.cs index 6a6ed6f..417ce8c 100644 --- a/LibreHardwareMonitorLib/Hardware/Cpu/GenericCpu.cs +++ b/LibreHardwareMonitorLib/Hardware/Cpu/GenericCpu.cs @@ -79,9 +79,9 @@ namespace LibreHardwareMonitor.Hardware.CPU if (HasTimeStampCounter) { - ulong mask = ThreadAffinity.Set(1UL << cpuId[0][0].Thread); + GroupAffinity previousAffinity = ThreadAffinity.Set(cpuId[0][0].Affinity); EstimateTimeStampCounterFrequency(out _estimatedTimeStampCounterFrequency, out _estimatedTimeStampCounterFrequencyError); - ThreadAffinity.Set(mask); + ThreadAffinity.Set(previousAffinity); } else { @@ -182,9 +182,9 @@ namespace LibreHardwareMonitor.Hardware.CPU error = beginError + endError; } - private static void AppendMsrData(StringBuilder r, uint msr, int thread) + private static void AppendMsrData(StringBuilder r, uint msr, GroupAffinity affinity) { - if (Ring0.ReadMsr(msr, out uint eax, out uint edx, 1UL << thread)) + if (Ring0.ReadMsr(msr, out uint eax, out uint edx, affinity)) { r.Append(" "); r.Append(msr.ToString("X8", CultureInfo.InvariantCulture)); @@ -241,7 +241,7 @@ namespace LibreHardwareMonitor.Hardware.CPU r.AppendLine(); r.AppendLine(" MSR EDX EAX"); foreach (uint msr in msrArray) - AppendMsrData(r, msr, _cpuId[i][0].Thread); + AppendMsrData(r, msr, _cpuId[i][0].Affinity); r.AppendLine(); } @@ -255,7 +255,7 @@ namespace LibreHardwareMonitor.Hardware.CPU if (HasTimeStampCounter && _isInvariantTimeStampCounter) { // make sure always the same thread is used - ulong mask = ThreadAffinity.Set(1UL << _cpuId[0][0].Thread); + GroupAffinity previousAffinity = ThreadAffinity.Set(_cpuId[0][0].Affinity); // read time before and after getting the TSC to estimate the error long firstTime = Stopwatch.GetTimestamp(); @@ -263,7 +263,7 @@ namespace LibreHardwareMonitor.Hardware.CPU long time = Stopwatch.GetTimestamp(); // restore the thread affinity mask - ThreadAffinity.Set(mask); + ThreadAffinity.Set(previousAffinity); double delta = (double)(time - _lastTime) / Stopwatch.Frequency; double error = (double)(time - firstTime) / Stopwatch.Frequency; diff --git a/LibreHardwareMonitorLib/Hardware/Cpu/IntelCpu.cs b/LibreHardwareMonitorLib/Hardware/Cpu/IntelCpu.cs index d5cf6f1..59a2439 100644 --- a/LibreHardwareMonitorLib/Hardware/Cpu/IntelCpu.cs +++ b/LibreHardwareMonitorLib/Hardware/Cpu/IntelCpu.cs @@ -413,7 +413,7 @@ namespace LibreHardwareMonitor.Hardware.CPU float[] result = new float[_coreCount]; for (int i = 0; i < _coreCount; i++) { - if (Ring0.ReadMsr(IA32_TEMPERATURE_TARGET, out uint eax, out uint _, 1UL << _cpuId[i][0].Thread)) + if (Ring0.ReadMsr(IA32_TEMPERATURE_TARGET, out uint eax, out uint _, _cpuId[i][0].Affinity)) result[i] = (eax >> 16) & 0xFF; else result[i] = 100; @@ -461,7 +461,7 @@ namespace LibreHardwareMonitor.Hardware.CPU for (int i = 0; i < _coreTemperatures.Length; i++) { // if reading is valid - if (Ring0.ReadMsr(IA32_THERM_STATUS_MSR, out uint eax, out uint _, 1UL << _cpuId[i][0].Thread) && (eax & 0x80000000) != 0) + if (Ring0.ReadMsr(IA32_THERM_STATUS_MSR, out uint eax, out uint _, _cpuId[i][0].Affinity) && (eax & 0x80000000) != 0) { // get the dist from tjMax from bits 22:16 float deltaT = (eax & 0x007F0000) >> 16; @@ -493,7 +493,7 @@ namespace LibreHardwareMonitor.Hardware.CPU if (_packageTemperature != null) { // if reading is valid - if (Ring0.ReadMsr(IA32_PACKAGE_THERM_STATUS, out uint eax, out uint _, 1UL << _cpuId[0][0].Thread) && (eax & 0x80000000) != 0) + if (Ring0.ReadMsr(IA32_PACKAGE_THERM_STATUS, out uint eax, out uint _, _cpuId[0][0].Affinity) && (eax & 0x80000000) != 0) { // get the dist from tjMax from bits 22:16 float deltaT = (eax & 0x007F0000) >> 16; @@ -513,7 +513,7 @@ namespace LibreHardwareMonitor.Hardware.CPU for (int i = 0; i < _coreClocks.Length; i++) { System.Threading.Thread.Sleep(1); - if (Ring0.ReadMsr(IA32_PERF_STATUS, out uint eax, out uint _, 1UL << _cpuId[i][0].Thread)) + if (Ring0.ReadMsr(IA32_PERF_STATUS, out uint eax, out uint _, _cpuId[i][0].Affinity)) { newBusClock = TimeStampCounterFrequency / _timeStampCounterMultiplier; switch (_microArchitecture) diff --git a/LibreHardwareMonitorLib/Hardware/GroupAffinity.cs b/LibreHardwareMonitorLib/Hardware/GroupAffinity.cs new file mode 100644 index 0000000..f441cd4 --- /dev/null +++ b/LibreHardwareMonitorLib/Hardware/GroupAffinity.cs @@ -0,0 +1,94 @@ +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. +// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +// Copyright (C) LibreHardwareMonitor and Contributors. +// Partial Copyright (C) Michael Möller and Contributors. +// All Rights Reserved. + +namespace LibreHardwareMonitor.Hardware +{ + /// + /// This structure describes a group-specific affinity. + /// + public readonly struct GroupAffinity + { + public static GroupAffinity Undefined = new GroupAffinity(ushort.MaxValue, 0); + + /// + /// Initializes a new instance of the struct. + /// + /// The group. + /// The mask. + public GroupAffinity(ushort group, ulong mask) + { + Group = group; + Mask = mask; + } + + /// + /// Gets a single group affinity. + /// + /// The group. + /// The index. + /// . + public static GroupAffinity Single(ushort group, int index) + { + return new GroupAffinity(group, 1UL << index); + } + + /// + /// Gets the group. + /// + public ushort Group { get; } + + /// + /// Gets the mask. + /// + public ulong Mask { get; } + + /// + /// Determines whether the specified is equal to this instance. + /// + /// The to compare with this instance. + /// true if the specified is equal to this instance; otherwise, false. + public override bool Equals(object o) + { + if (o == null || GetType() != o.GetType()) + return false; + + + GroupAffinity a = (GroupAffinity)o; + return (Group == a.Group) && (Mask == a.Mask); + } + + /// + /// Returns a hash code for this instance. + /// + /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. + public override int GetHashCode() + { + return Group.GetHashCode() ^ Mask.GetHashCode(); + } + + /// + /// Implements the == operator. + /// + /// The a1. + /// The a2. + /// The result of the operator. + public static bool operator ==(GroupAffinity a1, GroupAffinity a2) + { + return (a1.Group == a2.Group) && (a1.Mask == a2.Mask); + } + + /// + /// Implements the != operator. + /// + /// The a1. + /// The a2. + /// The result of the operator. + public static bool operator !=(GroupAffinity a1, GroupAffinity a2) + { + return (a1.Group != a2.Group) || (a1.Mask != a2.Mask); + } + } +} diff --git a/LibreHardwareMonitorLib/Hardware/Memory/MemoryGroup.cs b/LibreHardwareMonitorLib/Hardware/Memory/MemoryGroup.cs index d34af23..52cb115 100644 --- a/LibreHardwareMonitorLib/Hardware/Memory/MemoryGroup.cs +++ b/LibreHardwareMonitorLib/Hardware/Memory/MemoryGroup.cs @@ -15,7 +15,7 @@ namespace LibreHardwareMonitor.Hardware.Memory public MemoryGroup(ISettings settings) { // No implementation for RAM on Unix systems - if (Software.OperatingSystem.IsLinux) + if (Software.OperatingSystem.IsUnix) { _hardware = new Hardware[0]; return; diff --git a/LibreHardwareMonitorLib/Hardware/Motherboard/Motherboard.cs b/LibreHardwareMonitorLib/Hardware/Motherboard/Motherboard.cs index b74d838..0a81806 100644 --- a/LibreHardwareMonitorLib/Hardware/Motherboard/Motherboard.cs +++ b/LibreHardwareMonitorLib/Hardware/Motherboard/Motherboard.cs @@ -49,7 +49,7 @@ namespace LibreHardwareMonitor.Hardware.Motherboard _customName = settings.GetValue(new Identifier(Identifier, "name").ToString(), _name); - if (Software.OperatingSystem.IsLinux) + if (Software.OperatingSystem.IsUnix) { _lmSensors = new LMSensors(); superIO = _lmSensors.SuperIO; diff --git a/LibreHardwareMonitorLib/Hardware/OpCode.cs b/LibreHardwareMonitorLib/Hardware/OpCode.cs index 4c3ab46..e97fe60 100644 --- a/LibreHardwareMonitorLib/Hardware/OpCode.cs +++ b/LibreHardwareMonitorLib/Hardware/OpCode.cs @@ -12,7 +12,7 @@ namespace LibreHardwareMonitor.Hardware { internal static class OpCode { - public static CpuidDelegate Cpuid; + public static CpuidDelegate CpuId; public static RdtscDelegate Rdtsc; private static IntPtr _codeBuffer; @@ -218,12 +218,12 @@ namespace LibreHardwareMonitor.Hardware { rdTscCode = Rdtsc64; - cpuidCode = Software.OperatingSystem.IsLinux ? CpuId64Linux : CpuId64Windows; + cpuidCode = Software.OperatingSystem.IsUnix ? CpuId64Linux : CpuId64Windows; } _size = (ulong)(rdTscCode.Length + cpuidCode.Length); - if (Software.OperatingSystem.IsLinux) + if (Software.OperatingSystem.IsUnix) { Assembly assembly = Assembly.Load("Mono.Posix, Version=2.0.0.0, Culture=neutral, " + "PublicKeyToken=0738eb9f132ed756"); Type sysCall = assembly.GetType("Mono.Unix.Native.Syscall"); @@ -255,15 +255,15 @@ namespace LibreHardwareMonitor.Hardware Rdtsc = Marshal.GetDelegateForFunctionPointer(_codeBuffer, typeof(RdtscDelegate)) as RdtscDelegate; IntPtr cpuidAddress = (IntPtr)((long)_codeBuffer + rdTscCode.Length); Marshal.Copy(cpuidCode, 0, cpuidAddress, cpuidCode.Length); - Cpuid = Marshal.GetDelegateForFunctionPointer(cpuidAddress, typeof(CpuidDelegate)) as CpuidDelegate; + CpuId = Marshal.GetDelegateForFunctionPointer(cpuidAddress, typeof(CpuidDelegate)) as CpuidDelegate; } public static void Close() { Rdtsc = null; - Cpuid = null; + CpuId = null; - if (Software.OperatingSystem.IsLinux) + if (Software.OperatingSystem.IsUnix) { Assembly assembly = Assembly.Load("Mono.Posix, Version=2.0.0.0, Culture=neutral, " + "PublicKeyToken=0738eb9f132ed756"); Type sysCall = assembly.GetType("Mono.Unix.Native.Syscall"); @@ -276,17 +276,17 @@ namespace LibreHardwareMonitor.Hardware } } - public static bool CpuidTx(uint index, uint ecxValue, out uint eax, out uint ebx, out uint ecx, out uint edx, ulong threadAffinityMask) + public static bool CpuIdTx(uint index, uint ecxValue, out uint eax, out uint ebx, out uint ecx, out uint edx, GroupAffinity affinity) { - ulong mask = ThreadAffinity.Set(threadAffinityMask); - if (mask == 0) + GroupAffinity previousAffinity = ThreadAffinity.Set(affinity); + if (previousAffinity == GroupAffinity.Undefined) { eax = ebx = ecx = edx = 0; return false; } - Cpuid(index, ecxValue, out eax, out ebx, out ecx, out edx); - ThreadAffinity.Set(mask); + CpuId(index, ecxValue, out eax, out ebx, out ecx, out edx); + ThreadAffinity.Set(previousAffinity); return true; } } diff --git a/LibreHardwareMonitorLib/Hardware/Ring0.cs b/LibreHardwareMonitorLib/Hardware/Ring0.cs index 04f4bab..e620973 100644 --- a/LibreHardwareMonitorLib/Hardware/Ring0.cs +++ b/LibreHardwareMonitorLib/Hardware/Ring0.cs @@ -23,7 +23,7 @@ namespace LibreHardwareMonitor.Hardware private static string _fileName; private static Mutex _isaBusMutex; - private static readonly StringBuilder Report = new StringBuilder(); + private static readonly StringBuilder _report = new StringBuilder(); public static bool IsOpen { @@ -138,7 +138,7 @@ namespace LibreHardwareMonitor.Hardware public static void Open() { // no implementation for unix systems - if (Software.OperatingSystem.IsLinux) + if (Software.OperatingSystem.IsUnix) return; if (_driver != null) @@ -146,7 +146,7 @@ namespace LibreHardwareMonitor.Hardware // clear the current report - Report.Length = 0; + _report.Length = 0; _driver = new KernelDriver("WinRing0_1_2_0"); _driver.Open(); @@ -164,7 +164,7 @@ namespace LibreHardwareMonitor.Hardware if (!_driver.IsOpen) { _driver.Delete(); - Report.AppendLine("Status: Opening driver failed after install"); + _report.AppendLine("Status: Opening driver failed after install"); } } else @@ -184,20 +184,20 @@ namespace LibreHardwareMonitor.Hardware if (!_driver.IsOpen) { _driver.Delete(); - Report.AppendLine("Status: Opening driver failed after reinstall"); + _report.AppendLine("Status: Opening driver failed after reinstall"); } } else { - Report.AppendLine("Status: Installing driver \"" + _fileName + "\" failed" + (File.Exists(_fileName) ? " and file exists" : string.Empty)); - Report.AppendLine("First Exception: " + errorFirstInstall); - Report.AppendLine("Second Exception: " + errorSecondInstall); + _report.AppendLine("Status: Installing driver \"" + _fileName + "\" failed" + (File.Exists(_fileName) ? " and file exists" : string.Empty)); + _report.AppendLine("First Exception: " + errorFirstInstall); + _report.AppendLine("Second Exception: " + errorSecondInstall); } } } else { - Report.AppendLine("Status: Extracting driver failed"); + _report.AppendLine("Status: Extracting driver failed"); } try @@ -280,20 +280,15 @@ namespace LibreHardwareMonitor.Hardware { } } } - - public static ulong ThreadAffinitySet(ulong mask) - { - return ThreadAffinity.Set(mask); - } - + public static string GetReport() { - if (Report.Length > 0) + if (_report.Length > 0) { StringBuilder r = new StringBuilder(); r.AppendLine("Ring0"); r.AppendLine(); - r.Append(Report); + r.Append(_report); r.AppendLine(); return r.ToString(); } @@ -342,11 +337,11 @@ namespace LibreHardwareMonitor.Hardware return result; } - public static bool ReadMsr(uint index, out uint eax, out uint edx, ulong threadAffinityMask) + public static bool ReadMsr(uint index, out uint eax, out uint edx, GroupAffinity affinity) { - ulong mask = ThreadAffinity.Set(threadAffinityMask); + GroupAffinity previousAffinity = ThreadAffinity.Set(affinity); bool result = ReadMsr(index, out eax, out edx); - ThreadAffinity.Set(mask); + ThreadAffinity.Set(previousAffinity); return result; } diff --git a/LibreHardwareMonitorLib/Hardware/SMBios.cs b/LibreHardwareMonitorLib/Hardware/SMBios.cs index fe169d9..7d639b9 100644 --- a/LibreHardwareMonitorLib/Hardware/SMBios.cs +++ b/LibreHardwareMonitorLib/Hardware/SMBios.cs @@ -581,7 +581,7 @@ namespace LibreHardwareMonitor.Hardware public SMBios() { - if (Software.OperatingSystem.IsLinux) + if (Software.OperatingSystem.IsUnix) { _raw = null; diff --git a/LibreHardwareMonitorLib/Hardware/Storage/DebugSmart.cs b/LibreHardwareMonitorLib/Hardware/Storage/DebugSmart.cs index defa547..c0b8355 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/DebugSmart.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/DebugSmart.cs @@ -4,10 +4,6 @@ // Partial Copyright (C) Michael Möller and Contributors. // All Rights Reserved. -using System; -using System.Collections.Generic; -using LibreHardwareMonitor.Interop; - namespace LibreHardwareMonitor.Hardware.Storage { #if DEBUG diff --git a/LibreHardwareMonitorLib/Hardware/Storage/StorageGroup.cs b/LibreHardwareMonitorLib/Hardware/Storage/StorageGroup.cs index 614cf85..cffb153 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/StorageGroup.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/StorageGroup.cs @@ -16,7 +16,7 @@ namespace LibreHardwareMonitor.Hardware.Storage public StorageGroup(ISettings settings) { - if (Software.OperatingSystem.IsLinux) + if (Software.OperatingSystem.IsUnix) return; //https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-diskdrive diff --git a/LibreHardwareMonitorLib/Hardware/ThreadAffinity.cs b/LibreHardwareMonitorLib/Hardware/ThreadAffinity.cs index 1476de9..c4fadbc 100644 --- a/LibreHardwareMonitorLib/Hardware/ThreadAffinity.cs +++ b/LibreHardwareMonitorLib/Hardware/ThreadAffinity.cs @@ -5,38 +5,122 @@ // All Rights Reserved. using System; -using System.Runtime.InteropServices; +using LibreHardwareMonitor.Interop; namespace LibreHardwareMonitor.Hardware { internal static class ThreadAffinity { - public static ulong Set(ulong mask) + /// + /// Initializes static members of the class. + /// + static ThreadAffinity() { - if (mask == 0) - return 0; + ProcessorGroupCount = Software.OperatingSystem.IsUnix ? 1 : Kernel32.GetActiveProcessorGroupCount(); + if (ProcessorGroupCount < 1) + ProcessorGroupCount = 1; + } - if (Software.OperatingSystem.IsLinux) + /// + /// Gets the processor group count. + /// + public static int ProcessorGroupCount { get; } + + /// + /// Returns true if the is valid. + /// + /// The affinity. + /// true if the specified affinity is valid; otherwise, false. + public static bool IsValid(GroupAffinity affinity) + { + if (Software.OperatingSystem.IsUnix) { - ulong result = 0; - if (Interop.LibC.sched_getaffinity(0, (IntPtr)Marshal.SizeOf(result), ref result) != 0) - return 0; + if (affinity.Group > 0) + return false; + } - return Interop.LibC.sched_setaffinity(0, (IntPtr)Marshal.SizeOf(mask), ref mask) != 0 ? (ulong) 0 : result; + try + { + GroupAffinity previousAffinity = Set(affinity); + if (previousAffinity == GroupAffinity.Undefined) + return false; + + + Set(previousAffinity); + return true; + } + catch + { + return false; + } + } + + /// + /// Sets the processor group affinity for the current thread. + /// + /// The processor group affinity. + /// The previous processor group affinity. + public static GroupAffinity Set(GroupAffinity affinity) + { + if (affinity == GroupAffinity.Undefined) + return GroupAffinity.Undefined; + + + if (Software.OperatingSystem.IsUnix) + { + if (affinity.Group > 0) + throw new ArgumentOutOfRangeException(nameof(affinity)); + + + ulong result = 0; + if (LibC.sched_getaffinity(0, (IntPtr)8, ref result) != 0) + return GroupAffinity.Undefined; + + + ulong mask = affinity.Mask; + if (LibC.sched_setaffinity(0, (IntPtr)8, ref mask) != 0) + return GroupAffinity.Undefined; + + + return new GroupAffinity(0, result); } UIntPtr uIntPtrMask; try { - uIntPtrMask = (UIntPtr)mask; + uIntPtrMask = (UIntPtr)affinity.Mask; } catch (OverflowException) { - throw new ArgumentOutOfRangeException(nameof(mask)); + throw new ArgumentOutOfRangeException(nameof(affinity)); + } + + var groupAffinity = new Kernel32.GROUP_AFFINITY { Group = affinity.Group, Mask = uIntPtrMask }; + + IntPtr currentThread = Kernel32.GetCurrentThread(); + + try + { + if (Kernel32.SetThreadGroupAffinity(currentThread, + ref groupAffinity, + out Kernel32.GROUP_AFFINITY previousGroupAffinity)) + { + return new GroupAffinity(previousGroupAffinity.Group, (ulong)previousGroupAffinity.Mask); + } + + return GroupAffinity.Undefined; + } + catch (EntryPointNotFoundException) + { + if (affinity.Group > 0) + throw new ArgumentOutOfRangeException(nameof(affinity)); + + + ulong previous = (ulong)Kernel32.SetThreadAffinityMask(currentThread, uIntPtrMask); + + return new GroupAffinity(0, previous); } - return (ulong)Interop.Kernel32.SetThreadAffinityMask(Interop.Kernel32.GetCurrentThread(), uIntPtrMask); } } } - diff --git a/LibreHardwareMonitorLib/Interop/Kernel32.cs b/LibreHardwareMonitorLib/Interop/Kernel32.cs index 77f3d64..187d41f 100644 --- a/LibreHardwareMonitorLib/Interop/Kernel32.cs +++ b/LibreHardwareMonitorLib/Interop/Kernel32.cs @@ -209,6 +209,12 @@ namespace LibreHardwareMonitor.Interop [DllImport(DllName, CallingConvention = CallingConvention.Winapi)] internal static extern IntPtr GetCurrentThread(); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi)] + public static extern ushort GetActiveProcessorGroupCount(); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi)] + public static extern bool SetThreadGroupAffinity(IntPtr thread, ref GROUP_AFFINITY groupAffinity, out GROUP_AFFINITY previousGroupAffinity); [DllImport(DllName, CallingConvention = CallingConvention.Winapi)] internal static extern IntPtr VirtualAlloc(IntPtr lpAddress, UIntPtr dwSize, MEM flAllocationType, PAGE flProtect); @@ -245,6 +251,18 @@ namespace LibreHardwareMonitor.Interop [DllImport(DllName, CallingConvention = CallingConvention.Winapi, SetLastError = true)] internal static extern int GetSystemFirmwareTable(Provider firmwareTableProviderSignature, int firmwareTableID, IntPtr firmwareTableBuffer, int bufferSize); + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct GROUP_AFFINITY + { + public UIntPtr Mask; + + [MarshalAs(UnmanagedType.U2)] + public ushort Group; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3, ArraySubType = UnmanagedType.U2)] + public ushort[] Reserved; + } + internal enum DFP : uint { DFP_GET_VERSION = 0x00074080, diff --git a/LibreHardwareMonitorLib/Interop/NvidiaML.cs b/LibreHardwareMonitorLib/Interop/NvidiaML.cs index 28d6f07..7d12901 100644 --- a/LibreHardwareMonitorLib/Interop/NvidiaML.cs +++ b/LibreHardwareMonitorLib/Interop/NvidiaML.cs @@ -36,7 +36,7 @@ namespace LibreHardwareMonitor.Interop return true; } - if (Software.OperatingSystem.IsLinux) + if (Software.OperatingSystem.IsUnix) { try { @@ -151,7 +151,7 @@ namespace LibreHardwareMonitor.Interop { if (IsAvailable) { - if (Software.OperatingSystem.IsLinux) + if (Software.OperatingSystem.IsUnix) { nvmlShutdown(); } @@ -171,7 +171,7 @@ namespace LibreHardwareMonitor.Interop if (IsAvailable) { NvmlDevice nvmlDevice; - if (Software.OperatingSystem.IsLinux) + if (Software.OperatingSystem.IsUnix) { try { @@ -199,7 +199,7 @@ namespace LibreHardwareMonitor.Interop if (IsAvailable) { NvmlDevice nvmlDevice; - if (Software.OperatingSystem.IsLinux) + if (Software.OperatingSystem.IsUnix) { if (nvmlDeviceGetHandleByPciBusId(pciBusId, out nvmlDevice) == NvmlReturn.Success) return nvmlDevice; @@ -218,7 +218,7 @@ namespace LibreHardwareMonitor.Interop if (IsAvailable) { int powerUsage; - if (Software.OperatingSystem.IsLinux) + if (Software.OperatingSystem.IsUnix) { if (nvmlDeviceGetPowerUsage(nvmlDevice, out powerUsage) == NvmlReturn.Success) return powerUsage; @@ -237,7 +237,7 @@ namespace LibreHardwareMonitor.Interop if (IsAvailable) { uint pcieThroughput; - if (Software.OperatingSystem.IsLinux) + if (Software.OperatingSystem.IsUnix) { if (nvmlDeviceGetPcieThroughput(nvmlDevice, counter, out pcieThroughput) == NvmlReturn.Success) return pcieThroughput; diff --git a/LibreHardwareMonitorLib/LibreHardwareMonitorLib.csproj b/LibreHardwareMonitorLib/LibreHardwareMonitorLib.csproj index 2d70cc4..877f8a7 100644 --- a/LibreHardwareMonitorLib/LibreHardwareMonitorLib.csproj +++ b/LibreHardwareMonitorLib/LibreHardwareMonitorLib.csproj @@ -43,6 +43,7 @@ + diff --git a/LibreHardwareMonitorLib/Software/OperatingSystem.cs b/LibreHardwareMonitorLib/Software/OperatingSystem.cs index c9e881e..bdd7657 100644 --- a/LibreHardwareMonitorLib/Software/OperatingSystem.cs +++ b/LibreHardwareMonitorLib/Software/OperatingSystem.cs @@ -14,7 +14,7 @@ namespace LibreHardwareMonitor.Software { // The operating system doesn't change during execution so let's query it just one time. PlatformID platform = Environment.OSVersion.Platform; - IsLinux = platform == PlatformID.Unix || platform == PlatformID.MacOSX; + IsUnix = platform == PlatformID.Unix || platform == PlatformID.MacOSX; if (Environment.Is64BitOperatingSystem) Is64Bit = true; @@ -22,6 +22,6 @@ namespace LibreHardwareMonitor.Software public static bool Is64Bit { get; } - public static bool IsLinux { get; } + public static bool IsUnix { get; } } }