diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..e3cf04c --- /dev/null +++ b/.editorconfig @@ -0,0 +1,18 @@ +# +# Documentation: http://EditorConfig.org +# VS15 plug-in: http://visualstudiogallery.msdn.microsoft.com/c8bccfe2-650c-4b42-bc5c-845e21f96328 +# Natively supported in VS17 +# +# Configure editor for this project to match original project indentation scheme. + +# top-most EditorConfig file +root = true + +[*] +trim_trailing_whitespace = true + +[*.{cs,vb}] +indent_style = space +indent_size = 2 +dotnet_style_object_initializer = true:suggestion +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion \ No newline at end of file diff --git a/Hardware/CPU/AMD17CPU.cs b/Hardware/CPU/AMD17CPU.cs new file mode 100644 index 0000000..6c60e3e --- /dev/null +++ b/Hardware/CPU/AMD17CPU.cs @@ -0,0 +1,516 @@ +//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) 2016-2017 Sebastian Grams +//Copyright (C) 2016-2017 Aqua Computer + +using System; +using System.Collections.Generic; +//using System.Linq; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Text; +using System.Threading; + +namespace OpenHardwareMonitor.Hardware.CPU +{ + internal sealed class AMD17CPU : AMDCPU + { + //counter, to create sensor index values + public int sensor_temperatures = 0; + public int sensor_power = 0; + public int sensor_current = 0; + public int sensor_voltage = 0; + public int sensor_clock = 0; + public int sensor_multi = 0; + + //register index names for CPUID[] + private const int EAX = 0; + private const int EBX = 1; + private const int ECX = 2; + private const int EDX = 3; + + //zen register defninitions + public const uint PERF_CTL_0 = 0xC0010000; + public const uint PERF_CTR_0 = 0xC0010004; + public const uint HWCR = 0xC0010015; + + public const uint MSR_PSTATE_L = 0xC0010061; + public const uint MSR_PSTATE_C = 0xC0010062; + public const uint MSR_PSTATE_S = 0xC0010063; + public const uint MSR_PSTATE_0 = 0xC0010064; + + public const uint MSR_PWR_UNIT = 0xC0010299; + public const uint MSR_CORE_ENERGY_STAT = 0xC001029A; + public const uint MSR_PKG_ENERGY_STAT = 0xC001029B; + public const uint MSR_HARDWARE_PSTATE_STATUS = 0xC0010293; + public const uint COFVID_STATUS = 0xC0010071; + public const uint FAMILY_17H_PCI_CONTROL_REGISTER = 0x60; + public const uint FAMILY_17H_MODEL_01_MISC_CONTROL_DEVICE_ID = 0x1463; + public const uint F17H_M01H_THM_TCON_CUR_TMP = 0x00059800; + public const uint F17H_M01H_SVI = 0x0005A000; + + #region Processor + private class Processor + { + private AMD17CPU hw = null; + private DateTime last_pwr_time = new DateTime(0); + private uint last_pwr_value = 0; + + public Sensor packagePower { get; set; } + + public Processor(Hardware _hw) + { + this.hw = (AMD17CPU)_hw; + nodes = new List(); + + packagePower = new Sensor("Package Power", hw.sensor_power++, SensorType.Power, hw, hw.settings); + coreTemperatureTctl = new Sensor("Core (Tctl)", hw.sensor_temperatures++, SensorType.Temperature, hw, hw.settings); + coreTemperatureTdie = new Sensor("Core (Tdie)", hw.sensor_temperatures++, SensorType.Temperature, hw, hw.settings); + coreVoltage = new Sensor("Core (SVI2)", hw.sensor_voltage++, SensorType.Voltage, hw, hw.settings); + socVoltage = new Sensor("SoC (SVI2)", hw.sensor_voltage++, SensorType.Voltage, hw, hw.settings); + //node.coreCurrent = new Sensor("Core Current", hw.sensor_current++, SensorType.Current, hw, hw.settings); + //node.socCurrent = new Sensor("SoC Current", hw.sensor_current++, SensorType.Current, hw,hw.settings); + } + + #region UpdateSensors + public void UpdateSensors() + { + //var node = nodes.FirstOrDefault(); + var node = nodes[0]; + if (node == null) + return; + //var core = node.cores.FirstOrDefault(); + Core core = node.cores[0]; + if (core == null) + return; + //CPUID cpu = core.threads.FirstOrDefault(); + CPUID cpu = core.threads[0]; + if (cpu == null) + return; + uint eax, edx; + + ulong mask = Ring0.ThreadAffinitySet(1UL << cpu.Thread); + + //MSRC001_0299 + //TU [19:16] + //ESU [12:8] -> Unit 15.3 micro Joule per increment + //PU [3:0] + Ring0.Rdmsr(MSR_PWR_UNIT, out eax, out edx); + int tu = (int)((eax >> 16) & 0xf); + int esu = (int)((eax >> 12) & 0xf); + int pu = (int)(eax & 0xf); + + //MSRC001_029B + //total_energy [31:0] + DateTime sample_time = DateTime.Now; + Ring0.Rdmsr(MSR_PKG_ENERGY_STAT, out eax, out edx); + uint total_energy = eax; + + //THM_TCON_CUR_TMP + //CUR_TEMP [31:21] + uint temperature = 0; + Ring0.WritePciConfig(Ring0.GetPciAddress(0, 0, 0), FAMILY_17H_PCI_CONTROL_REGISTER, F17H_M01H_THM_TCON_CUR_TMP); + Ring0.ReadPciConfig(Ring0.GetPciAddress(0, 0, 0), FAMILY_17H_PCI_CONTROL_REGISTER + 4, out temperature); + + //SVI0_TFN_PLANE0 [0] + //SVI0_TFN_PLANE1 [1] + uint smusvi0_tfn = 0; + Ring0.WritePciConfig(Ring0.GetPciAddress(0, 0, 0), FAMILY_17H_PCI_CONTROL_REGISTER, F17H_M01H_SVI + 0x8); + Ring0.ReadPciConfig(Ring0.GetPciAddress(0, 0, 0), FAMILY_17H_PCI_CONTROL_REGISTER + 4, out smusvi0_tfn); + + //SVI0_PLANE0_VDDCOR [24:16] + //SVI0_PLANE0_IDDCOR [7:0] + uint smusvi0_tel_plane0 = 0; + Ring0.WritePciConfig(Ring0.GetPciAddress(0, 0, 0), FAMILY_17H_PCI_CONTROL_REGISTER, F17H_M01H_SVI + 0xc); + Ring0.ReadPciConfig(Ring0.GetPciAddress(0, 0, 0), FAMILY_17H_PCI_CONTROL_REGISTER + 4, out smusvi0_tel_plane0); + + //SVI0_PLANE1_VDDCOR [24:16] + //SVI0_PLANE1_IDDCOR [7:0] + uint smusvi0_tel_plane1 = 0; + Ring0.WritePciConfig(Ring0.GetPciAddress(0, 0, 0), FAMILY_17H_PCI_CONTROL_REGISTER, F17H_M01H_SVI + 0x10); + Ring0.ReadPciConfig(Ring0.GetPciAddress(0, 0, 0), FAMILY_17H_PCI_CONTROL_REGISTER + 4, out smusvi0_tel_plane1); + + Ring0.ThreadAffinitySet(mask); + + //power consumption + //power.Value = (float) ((double)pu * 0.125); + //esu = 15.3 micro Joule per increment + if (last_pwr_time.Ticks == 0) + { + last_pwr_time = sample_time; + last_pwr_value = total_energy; + } + //ticks diff + TimeSpan time = sample_time - last_pwr_time; + long pwr; + if (last_pwr_value <= total_energy) + pwr = total_energy - last_pwr_value; + else + pwr = (0xffffffff - last_pwr_value) + total_energy; + + //update for next sample + last_pwr_time = sample_time; + last_pwr_value = total_energy; + + double energy = 15.3e-6 * pwr; + energy /= time.TotalSeconds; + + packagePower.Value = (float)energy; + hw.ActivateSensor(packagePower); + + //current temp Bit [31:21] + temperature = (temperature >> 21) * 125; + float offset = 0.0f; + if (cpu.Name != null && (cpu.Name.Contains("1600X") || cpu.Name.Contains("1700X") || cpu.Name.Contains("1800X"))) + offset = -20.0f; + else if (cpu.Name != null && (cpu.Name.Contains("1920X") || cpu.Name.Contains("1950X"))) + offset = -27.0f; + else if (cpu.Name != null && (cpu.Name.Contains("1910") || cpu.Name.Contains("1920"))) + offset = -10.0f; + + coreTemperatureTctl.Value = (temperature * 0.001f); + coreTemperatureTdie.Value = (temperature * 0.001f) + offset; + hw.ActivateSensor(coreTemperatureTctl); + hw.ActivateSensor(coreTemperatureTdie); + + //voltage + double VIDStep = 0.00625; + double vcc; + uint svi0_plane_x_vddcor; + uint svi0_plane_x_iddcor; + + //Core + if ((smusvi0_tfn & 0x01) == 0) + { + svi0_plane_x_vddcor = (smusvi0_tel_plane0 >> 16) & 0xff; + svi0_plane_x_iddcor = smusvi0_tel_plane0 & 0xff; + vcc = 1.550 - (double)VIDStep * svi0_plane_x_vddcor; + coreVoltage.Value = (float)vcc; + hw.ActivateSensor(coreVoltage); + //coreCurrent.Value = (float)(svi0_plane_x_iddcor * 1); + //hw.ActivateSensor(coreCurrent); + } + + //SoC + if ((smusvi0_tfn & 0x02) == 0) + { + svi0_plane_x_vddcor = (smusvi0_tel_plane1 >> 16) & 0xff; + svi0_plane_x_iddcor = smusvi0_tel_plane1 & 0xff; + vcc = 1.550 - (double)VIDStep * svi0_plane_x_vddcor; + socVoltage.Value = (float)vcc; + hw.ActivateSensor(socVoltage); + //socCurrent.Value = (float)(svi0_plane_x_iddcor * 1); + //hw.ActivateSensor(socCurrent); + } + + } + #endregion + + public void appendThread(CPUID thread, int numa_id, int core_id) + { + NumaNode node = null; + //node = (from x in nodes + // where x.nodeId == numa_id + // select x).FirstOrDefault(); + foreach (var n in nodes) + { + if (n.nodeId == numa_id) + node = n; + } + if (node == null) + { + node = new NumaNode(hw); + node.nodeId = numa_id; + node.parent = this; + nodes.Add(node); + } + + if (thread != null) + node.appendThread(thread, core_id); + } + + public Sensor coreTemperatureTctl { get; set; } + public Sensor coreTemperatureTdie { get; set; } + + public Sensor coreVoltage { get; set; } + //public Sensor coreCurrent { get; set; } + public Sensor socVoltage { get; set; } + //public Sensor socCurrent { get; set; } + + public List nodes { get; set; } + } + #endregion + + #region NumaNode + private class NumaNode + { + private AMD17CPU hw = null; + + public NumaNode(Hardware _hw) + { + cores = new List(); + nodeId = -1; + this.hw = (AMD17CPU)_hw; + } + + public void appendThread(CPUID thread, int core_id) + { + Core core = null; + //Core core = (from x in cores + // where x.coreId == core_id + // select x).FirstOrDefault(); + foreach (var c in cores) + { + if (c.coreId == core_id) + core = c; + } + if (core == null) + { + core = new Core(hw); + core.coreId = core_id; + core.parent = this; + + core.clock = new Sensor("Core #" + core.coreId.ToString(), hw.sensor_clock++, SensorType.Clock, hw, hw.settings); + core.multiplier = new Sensor("Core #" + core.coreId.ToString(), hw.sensor_multi++, SensorType.Factor, hw, hw.settings); + core.power = new Sensor("Core #" + core.coreId.ToString() + " (SMU)", hw.sensor_power++, SensorType.Power, hw, hw.settings); + core.vcore = new Sensor("Core #" + core.coreId.ToString() + " VID", hw.sensor_voltage++, SensorType.Voltage, hw, hw.settings); + cores.Add(core); + } + + if (thread != null) + core.threads.Add(thread); + } + + #region UpdateSensors + public void UpdateSensors() + { + + + } + #endregion + + public int nodeId { get; set; } + public List cores { get; set; } + + public Processor parent { get; set; } + } + #endregion + + #region Core + private class Core + { + private AMD17CPU hw = null; + + public Core(Hardware _hw) + { + threads = new List(); + coreId = -1; + hw = (AMD17CPU)_hw; + } + + DateTime last_pwr_time = new DateTime(0); + uint last_pwr_value = 0; + + #region UpdateSensors + public void UpdateSensors() + { + //CPUID cpu = threads.FirstOrDefault(); + CPUID cpu = threads[0]; + if (cpu == null) + return; + uint eax, edx; + ulong mask = Ring0.ThreadAffinitySet(1UL << cpu.Thread); + + + //MSRC001_0299 + //TU [19:16] + //ESU [12:8] -> Unit 15.3 micro Joule per increment + //PU [3:0] + Ring0.Rdmsr(MSR_PWR_UNIT, out eax, out edx); + int tu = (int)((eax >> 16) & 0xf); + int esu = (int)((eax >> 12) & 0xf); + int pu = (int)(eax & 0xf); + + //MSRC001_029A + //total_energy [31:0] + DateTime sample_time = DateTime.Now; + Ring0.Rdmsr(MSR_CORE_ENERGY_STAT, out eax, out edx); + uint total_energy = eax; + + //MSRC001_0293 + //CurHwPstate [24:22] + //CurCpuVid [21:14] + //CurCpuDfsId [13:8] + //CurCpuFid [7:0] + Ring0.Rdmsr(MSR_HARDWARE_PSTATE_STATUS, out eax, out edx); + int CurHwPstate = (int)((eax >> 22) & 0x3); + int CurCpuVid = (int)((eax >> 14) & 0xff); + int CurCpuDfsId = (int)((eax >> 8) & 0x3f); + int CurCpuFid = (int)(eax & 0xff); + + //MSRC001_0064 + x + //IddDiv [31:30] + //IddValue [29:22] + //CpuVid [21:14] + //CpuDfsId [13:8] + //CpuFid [7:0] + //Ring0.Rdmsr(MSR_PSTATE_0 + (uint)CurHwPstate, out eax, out edx); + //int IddDiv = (int)((eax >> 30) & 0x03); + //int IddValue = (int)((eax >> 22) & 0xff); + //int CpuVid = (int)((eax >> 14) & 0xff); + + Ring0.ThreadAffinitySet(mask); + + //clock + //CoreCOF is (Core::X86::Msr::PStateDef[CpuFid[7:0]] / Core::X86::Msr::PStateDef[CpuDfsId]) * 200 + clock.Value = (float)((double)CurCpuFid / (double)CurCpuDfsId * 200.0); + hw.ActivateSensor(clock); + + //multiplier + multiplier.Value = (float)((double)CurCpuFid / (double)CurCpuDfsId * 2.0); + hw.ActivateSensor(multiplier); + + //Voltage + double VIDStep = 0.00625; + double vcc = 1.550 - (double)VIDStep * CurCpuVid; + vcore.Value = (float)vcc; + hw.ActivateSensor(vcore); + + //power consumption + //power.Value = (float) ((double)pu * 0.125); + //esu = 15.3 micro Joule per increment + if (last_pwr_time.Ticks == 0) + { + last_pwr_time = sample_time; + last_pwr_value = total_energy; + } + //ticks diff + TimeSpan time = sample_time - last_pwr_time; + long pwr; + if (last_pwr_value <= total_energy) + pwr = total_energy - last_pwr_value; + else + pwr = (0xffffffff - last_pwr_value) + total_energy; + + //update for next sample + last_pwr_time = sample_time; + last_pwr_value = total_energy; + + double energy = 15.3e-6 * pwr; + energy /= time.TotalSeconds; + + power.Value = (float)energy; + hw.ActivateSensor(power); + + } + #endregion + + public Sensor clock { get; set; } + public Sensor vcore { get; set; } + public Sensor power { get; set; } + public Sensor multiplier { get; set; } + + public int coreId { get; set; } + public List threads { get; set; } + public NumaNode parent { get; set; } + } + #endregion + + private Processor ryzen = null; + + public AMD17CPU(int processorIndex, CPUID[][] cpuid, ISettings settings) + : base(processorIndex, cpuid, settings) + { + //add all numa nodes + //Register ..1E_ECX, [10:8] + 1 + ryzen = new Processor(this); + int NodesPerProcessor = 1 + (int)((cpuid[0][0].ExtData[0x1e, ECX] >> 8) & 0x7); + + //add all numa nodes + foreach (CPUID[] cpu in cpuid) + { + CPUID thread = cpu[0]; + + //coreID + //Register ..1E_EBX, [7:0] + int core_id = (int)(thread.ExtData[0x1e, EBX] & 0xff); + + //nodeID + //Register ..1E_ECX, [7:0] + int node_id = (int)(thread.ExtData[0x1e, ECX] & 0xff); + + ryzen.appendThread(null, node_id, core_id); + } + + //add all threads to numa nodes and specific core + foreach (CPUID[] cpu in cpuid) + { + CPUID thread = cpu[0]; + + //coreID + //Register ..1E_EBX, [7:0] + int core_id = (int)(thread.ExtData[0x1e, EBX] & 0xff); + + //nodeID + //Register ..1E_ECX, [7:0] + int node_id = (int)(thread.ExtData[0x1e, ECX] & 0xff); + + ryzen.appendThread(thread, node_id, core_id); + } + Update(); + } + + protected override uint[] GetMSRs() + { + return new uint[] { PERF_CTL_0, PERF_CTR_0, HWCR, MSR_PSTATE_0, COFVID_STATUS }; + } + + public override string GetReport() + { + StringBuilder r = new StringBuilder(); + r.Append(base.GetReport()); + r.Append("Ryzen"); + return r.ToString(); + } + + private string ReadFirstLine(Stream stream) + { + StringBuilder sb = new StringBuilder(); + try + { + stream.Seek(0, SeekOrigin.Begin); + int b = stream.ReadByte(); + while (b != -1 && b != 10) + { + sb.Append((char)b); + b = stream.ReadByte(); + } + } + catch { } + return sb.ToString(); + } + + public override void Update() + { + base.Update(); + + ryzen.UpdateSensors(); + foreach (NumaNode node in ryzen.nodes) + { + node.UpdateSensors(); + + foreach (Core c in node.cores) + { + c.UpdateSensors(); + } + } + } + + public override void Close() + { + base.Close(); + } + } +} diff --git a/Hardware/CPU/CPUGroup.cs b/Hardware/CPU/CPUGroup.cs index 98829d2..7373a46 100644 --- a/Hardware/CPU/CPUGroup.cs +++ b/Hardware/CPU/CPUGroup.cs @@ -102,9 +102,11 @@ namespace OpenHardwareMonitor.Hardware.CPU { case 0x14: case 0x15: case 0x16: - case 0x17: hardware.Add(new AMD10CPU(index, coreThreads, settings)); break; + case 0x17: + hardware.Add(new AMD17CPU(index, coreThreads, settings)); + break; default: hardware.Add(new GenericCPU(index, coreThreads, settings)); break; diff --git a/Hardware/CPU/CPUID.cs b/Hardware/CPU/CPUID.cs index e418dc4..3004e6a 100644 --- a/Hardware/CPU/CPUID.cs +++ b/Hardware/CPU/CPUID.cs @@ -186,6 +186,27 @@ namespace OpenHardwareMonitor.Hardware.CPU { corePerPackage = 1; threadMaskWith = 0; coreMaskWith = NextLog2(corePerPackage); + + if (this.family == 0x17) + { + //ApicIdCoreIdSize: APIC ID size. + //cores per DIE + //we need this for Ryzen 5 (4 cores, 8 threads) ans Ryzen 6 (6 cores, 12 threads) + //Ryzen 5: [core0][core1][dummy][dummy][core2][core3] (Core0 EBX = 00080800, Core2 EBX = 08080800) + uint max_cores_per_die = (cpuidExtData[8, 2] >> 12) & 0xF; + switch (max_cores_per_die) + { + 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; diff --git a/Hardware/Ring0.cs b/Hardware/Ring0.cs index 9f5a44c..c506c69 100644 --- a/Hardware/Ring0.cs +++ b/Hardware/Ring0.cs @@ -239,6 +239,10 @@ namespace OpenHardwareMonitor.Hardware { catch (UnauthorizedAccessException) { } } } + public static ulong ThreadAffinitySet(ulong mask) + { + return ThreadAffinity.Set(mask); + } public static string GetReport() { if (report.Length > 0) { diff --git a/OpenHardwareMonitorLib.csproj b/OpenHardwareMonitorLib.csproj index 9eb1e8d..fd6bf2f 100644 --- a/OpenHardwareMonitorLib.csproj +++ b/OpenHardwareMonitorLib.csproj @@ -62,6 +62,7 @@ +