mirror of
https://github.com/openhardwaremonitor/openhardwaremonitor
synced 2025-08-22 09:57:20 +00:00
Added AMD family 17h (Ryzen) CPU support.
This commit is contained in:
parent
f659aa0f60
commit
5748e67bf4
342
Hardware/CPU/AMD17CPU.cs
Normal file
342
Hardware/CPU/AMD17CPU.cs
Normal file
@ -0,0 +1,342 @@
|
||||
/*
|
||||
|
||||
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) 2020 Michael Möller <mmoeller@openhardwaremonitor.org>
|
||||
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace OpenHardwareMonitor.Hardware.CPU {
|
||||
|
||||
internal sealed class AMD17CPU : AMDCPU {
|
||||
|
||||
private readonly Core[] cores;
|
||||
|
||||
private readonly Sensor coreTemperature;
|
||||
private readonly Sensor tctlTemperature;
|
||||
private readonly Sensor ccdMaxTemperature;
|
||||
private readonly Sensor ccdAvgTemperature;
|
||||
private readonly Sensor[] ccdTemperatures;
|
||||
private readonly Sensor packagePowerSensor;
|
||||
private readonly Sensor coresPowerSensor;
|
||||
private readonly Sensor busClock;
|
||||
|
||||
private const uint FAMILY_17H_M01H_THM_TCON_TEMP = 0x00059800;
|
||||
private const uint FAMILY_17H_M01H_THM_TCON_TEMP_RANGE_SEL = 0x80000;
|
||||
private uint FAMILY_17H_M70H_CCD_TEMP(uint i) { return 0x00059954 + i * 4; }
|
||||
private const uint FAMILY_17H_M70H_CCD_TEMP_VALID = 0x800;
|
||||
private const uint MAX_CCD_COUNT = 8;
|
||||
|
||||
private const uint MSR_RAPL_PWR_UNIT = 0xC0010299;
|
||||
private const uint MSR_CORE_ENERGY_STAT = 0xC001029A;
|
||||
private const uint MSR_PKG_ENERGY_STAT = 0xC001029B;
|
||||
private const uint MSR_P_STATE_0 = 0xC0010064;
|
||||
private const uint MSR_FAMILY_17H_P_STATE = 0xc0010293;
|
||||
|
||||
private float energyUnitMultiplier = 0;
|
||||
private uint lastEnergyConsumed;
|
||||
private DateTime lastEnergyTime;
|
||||
|
||||
private readonly double timeStampCounterMultiplier;
|
||||
|
||||
private struct TctlOffsetItem {
|
||||
public string Name { get; set; }
|
||||
public float Offset { get; set; }
|
||||
}
|
||||
private IEnumerable<TctlOffsetItem> tctlOffsetItems = new[] {
|
||||
new TctlOffsetItem { Name = "AMD Ryzen 5 1600X", Offset = 20.0f },
|
||||
new TctlOffsetItem { Name = "AMD Ryzen 7 1700X", Offset = 20.0f },
|
||||
new TctlOffsetItem { Name = "AMD Ryzen 7 1800X", Offset = 20.0f },
|
||||
new TctlOffsetItem { Name = "AMD Ryzen 7 2700X", Offset = 10.0f },
|
||||
new TctlOffsetItem { Name = "AMD Ryzen Threadripper 19", Offset = 27.0f },
|
||||
new TctlOffsetItem { Name = "AMD Ryzen Threadripper 29", Offset = 27.0f }
|
||||
};
|
||||
private readonly float tctlOffset = 0.0f;
|
||||
|
||||
public AMD17CPU(int processorIndex, CPUID[][] cpuid, ISettings settings)
|
||||
: base(processorIndex, cpuid, settings)
|
||||
{
|
||||
string cpuName = cpuid[0][0].BrandString;
|
||||
if (!string.IsNullOrEmpty(cpuName)) {
|
||||
foreach (var item in tctlOffsetItems) {
|
||||
if (cpuName.StartsWith(item.Name)) {
|
||||
tctlOffset = item.Offset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
coreTemperature = new Sensor(
|
||||
"CPU Package", 0, SensorType.Temperature, this, new[] {
|
||||
new ParameterDescription("Offset [°C]", "Temperature offset.", 0)
|
||||
}, this.settings);
|
||||
|
||||
if (tctlOffset != 0.0f)
|
||||
tctlTemperature = new Sensor(
|
||||
"CPU Tctl", 1, true, SensorType.Temperature, this, new[] {
|
||||
new ParameterDescription("Offset [°C]", "Temperature offset.", 0)
|
||||
}, this.settings);
|
||||
|
||||
ccdMaxTemperature = new Sensor(
|
||||
"CPU CCD Max", 2, SensorType.Temperature, this, this.settings);
|
||||
|
||||
ccdAvgTemperature = new Sensor(
|
||||
"CPU CCD Average", 3, SensorType.Temperature, this, this.settings);
|
||||
|
||||
ccdTemperatures = new Sensor[MAX_CCD_COUNT];
|
||||
for (int i = 0; i < MAX_CCD_COUNT; i++) {
|
||||
ccdTemperatures[i] = new Sensor(
|
||||
"CPU CCD #" + (i + 1), i + 4, SensorType.Temperature, this,
|
||||
new[] {
|
||||
new ParameterDescription("Offset [°C]", "Temperature offset.", 0)
|
||||
}, this.settings);
|
||||
}
|
||||
|
||||
if (Ring0.Rdmsr(MSR_RAPL_PWR_UNIT, out uint eax, out _)) {
|
||||
energyUnitMultiplier = 1.0f / (1 << (int)((eax >> 8) & 0x1F));
|
||||
}
|
||||
|
||||
if (energyUnitMultiplier != 0) {
|
||||
if (Ring0.Rdmsr(MSR_PKG_ENERGY_STAT, out uint energyConsumed, out _)) {
|
||||
lastEnergyTime = DateTime.UtcNow;
|
||||
lastEnergyConsumed = energyConsumed;
|
||||
packagePowerSensor = new Sensor(
|
||||
"CPU Package", 0, SensorType.Power, this, settings);
|
||||
ActivateSensor(packagePowerSensor);
|
||||
}
|
||||
|
||||
coresPowerSensor = new Sensor("CPU Cores", 1, SensorType.Power, this,
|
||||
settings);
|
||||
}
|
||||
|
||||
busClock = new Sensor("Bus Speed", 0, SensorType.Clock, this, settings);
|
||||
timeStampCounterMultiplier = GetTimeStampCounterMultiplier();
|
||||
if (timeStampCounterMultiplier > 0) {
|
||||
busClock.Value = (float)(TimeStampCounterFrequency /
|
||||
timeStampCounterMultiplier);
|
||||
ActivateSensor(busClock);
|
||||
}
|
||||
|
||||
this.cores = new Core[coreCount];
|
||||
for (int i = 0; i < this.cores.Length; i++) {
|
||||
this.cores[i] = new Core(i, cpuid[i], this, settings);
|
||||
}
|
||||
}
|
||||
|
||||
protected override uint[] GetMSRs() {
|
||||
return new uint[] { MSR_P_STATE_0, MSR_FAMILY_17H_P_STATE,
|
||||
MSR_RAPL_PWR_UNIT, MSR_CORE_ENERGY_STAT, MSR_PKG_ENERGY_STAT };
|
||||
}
|
||||
|
||||
private IList<uint> GetSmnRegisters() {
|
||||
var registers = new List<uint>();
|
||||
registers.Add(FAMILY_17H_M01H_THM_TCON_TEMP);
|
||||
for (uint i = 0; i < MAX_CCD_COUNT; i++) {
|
||||
registers.Add(FAMILY_17H_M70H_CCD_TEMP(i));
|
||||
}
|
||||
return registers;
|
||||
}
|
||||
|
||||
public override string GetReport() {
|
||||
StringBuilder r = new StringBuilder();
|
||||
r.Append(base.GetReport());
|
||||
|
||||
r.Append("Time Stamp Counter Multiplier: ");
|
||||
r.AppendLine(timeStampCounterMultiplier.ToString(
|
||||
CultureInfo.InvariantCulture));
|
||||
r.AppendLine();
|
||||
|
||||
r.AppendLine("SMN Registers");
|
||||
r.AppendLine();
|
||||
r.AppendLine(" Register Value");
|
||||
var registers = GetSmnRegisters();
|
||||
for (int i = 0; i < registers.Count; i++)
|
||||
if (ReadSmnRegister(registers[i], out uint value)) {
|
||||
r.Append(" ");
|
||||
r.Append(registers[i].ToString("X8", CultureInfo.InvariantCulture));
|
||||
r.Append(" ");
|
||||
r.Append(value.ToString("X8", CultureInfo.InvariantCulture));
|
||||
r.AppendLine();
|
||||
}
|
||||
r.AppendLine();
|
||||
|
||||
return r.ToString();
|
||||
}
|
||||
|
||||
private double GetTimeStampCounterMultiplier() {
|
||||
Ring0.Rdmsr(MSR_P_STATE_0, out uint eax, out _);
|
||||
uint cpuDfsId = (eax >> 8) & 0x3f;
|
||||
uint cpuFid = eax & 0xff;
|
||||
return 2.0 * cpuFid / cpuDfsId;
|
||||
}
|
||||
|
||||
private bool ReadSmnRegister(uint address, out uint value) {
|
||||
if (!Ring0.WritePciConfig(0, 0x60, address)) {
|
||||
value = 0;
|
||||
return false;
|
||||
}
|
||||
return Ring0.ReadPciConfig(0, 0x64, out value);
|
||||
}
|
||||
|
||||
public override void Update() {
|
||||
base.Update();
|
||||
|
||||
uint value;
|
||||
if (ReadSmnRegister(FAMILY_17H_M01H_THM_TCON_TEMP, out value)) {
|
||||
float temperature = ((value >> 21) & 0x7FF) / 8.0f;
|
||||
if ((value & FAMILY_17H_M01H_THM_TCON_TEMP_RANGE_SEL) != 0)
|
||||
temperature -= 49;
|
||||
|
||||
if (tctlTemperature != null) {
|
||||
tctlTemperature.Value = temperature +
|
||||
tctlTemperature.Parameters[0].Value;
|
||||
ActivateSensor(tctlTemperature);
|
||||
}
|
||||
|
||||
temperature -= tctlOffset;
|
||||
|
||||
coreTemperature.Value = temperature +
|
||||
coreTemperature.Parameters[0].Value;
|
||||
ActivateSensor(coreTemperature);
|
||||
}
|
||||
|
||||
float maxTemperature = float.MinValue;
|
||||
int ccdCount = 0;
|
||||
float ccdTemperatureSum = 0;
|
||||
for (uint i = 0; i < MAX_CCD_COUNT; i++) {
|
||||
if (ReadSmnRegister(FAMILY_17H_M70H_CCD_TEMP(i), out value)) {
|
||||
if ((value & FAMILY_17H_M70H_CCD_TEMP_VALID) == 0)
|
||||
continue;
|
||||
|
||||
float temperature = (value & 0x7FF) / 8.0f - 49;
|
||||
temperature += ccdTemperatures[i].Parameters[0].Value;
|
||||
|
||||
if (temperature > maxTemperature)
|
||||
maxTemperature = temperature;
|
||||
ccdCount++;
|
||||
ccdTemperatureSum += temperature;
|
||||
|
||||
ccdTemperatures[i].Value = temperature;
|
||||
ActivateSensor(ccdTemperatures[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (ccdCount > 1) {
|
||||
ccdMaxTemperature.Value = maxTemperature;
|
||||
ActivateSensor(ccdMaxTemperature);
|
||||
|
||||
ccdAvgTemperature.Value = ccdTemperatureSum / ccdCount;
|
||||
ActivateSensor(ccdAvgTemperature);
|
||||
}
|
||||
|
||||
if (Ring0.Rdmsr(MSR_PKG_ENERGY_STAT, out uint energyConsumed, out _)) {
|
||||
|
||||
DateTime time = DateTime.UtcNow;
|
||||
float deltaTime = (float)(time - lastEnergyTime).TotalSeconds;
|
||||
if (deltaTime > 0.01) {
|
||||
|
||||
packagePowerSensor.Value = energyUnitMultiplier * unchecked(
|
||||
energyConsumed - lastEnergyConsumed) / deltaTime;
|
||||
lastEnergyTime = time;
|
||||
lastEnergyConsumed = energyConsumed;
|
||||
}
|
||||
}
|
||||
|
||||
float? coresPower = 0f;
|
||||
for (int i = 0; i < cores.Length; i++) {
|
||||
cores[i].Update();
|
||||
coresPower += cores[i].Power;
|
||||
}
|
||||
coresPowerSensor.Value = coresPower;
|
||||
|
||||
if (coresPower.HasValue) {
|
||||
ActivateSensor(coresPowerSensor);
|
||||
}
|
||||
}
|
||||
|
||||
private class Core {
|
||||
|
||||
private readonly AMD17CPU cpu;
|
||||
private readonly ulong threadAffinityMask;
|
||||
|
||||
private readonly Sensor powerSensor;
|
||||
private readonly Sensor clockSensor;
|
||||
|
||||
private DateTime lastEnergyTime;
|
||||
private uint lastEnergyConsumed;
|
||||
private float? power = null;
|
||||
|
||||
public Core(int index, CPUID[] threads, AMD17CPU cpu, ISettings settings)
|
||||
{
|
||||
this.cpu = cpu;
|
||||
this.threadAffinityMask = 1UL << threads[0].Thread;
|
||||
|
||||
string coreString = cpu.CoreString(index);
|
||||
this.powerSensor =
|
||||
new Sensor(coreString, index + 2, SensorType.Power, cpu, settings);
|
||||
this.clockSensor =
|
||||
new Sensor(coreString, index + 1, SensorType.Clock, cpu, settings);
|
||||
|
||||
if (cpu.energyUnitMultiplier != 0) {
|
||||
if (Ring0.RdmsrTx(MSR_CORE_ENERGY_STAT, out uint energyConsumed,
|
||||
out _, threadAffinityMask))
|
||||
{
|
||||
lastEnergyTime = DateTime.UtcNow;
|
||||
lastEnergyConsumed = energyConsumed;
|
||||
cpu.ActivateSensor(powerSensor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private double? GetMultiplier() {
|
||||
if (Ring0.Rdmsr(MSR_FAMILY_17H_P_STATE, out uint eax, out _)) {
|
||||
uint cpuDfsId = (eax >> 8) & 0x3f;
|
||||
uint cpuFid = eax & 0xff;
|
||||
return 2.0 * cpuFid / cpuDfsId;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public float? Power { get { return power; } }
|
||||
|
||||
public void Update() {
|
||||
DateTime energyTime = DateTime.MinValue;
|
||||
double? multiplier = null;
|
||||
|
||||
ulong mask = ThreadAffinity.Set(threadAffinityMask);
|
||||
if (Ring0.Rdmsr(MSR_CORE_ENERGY_STAT, out uint energyConsumed, out _)) {
|
||||
energyTime = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
multiplier = GetMultiplier();
|
||||
ThreadAffinity.Set(mask);
|
||||
|
||||
float deltaTime = (float)(energyTime - lastEnergyTime).TotalSeconds;
|
||||
if (deltaTime > 0.01) {
|
||||
power = cpu.energyUnitMultiplier *
|
||||
unchecked(energyConsumed - lastEnergyConsumed) / deltaTime;
|
||||
powerSensor.Value = power;
|
||||
lastEnergyTime = energyTime;
|
||||
lastEnergyConsumed = energyConsumed;
|
||||
}
|
||||
|
||||
if (multiplier.HasValue) {
|
||||
float? clock = (float?)(multiplier * cpu.busClock.Value);
|
||||
clockSensor.Value = clock;
|
||||
if (clock.HasValue)
|
||||
cpu.ActivateSensor(clockSensor);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
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) 2009-2014 Michael Möller <mmoeller@openhardwaremonitor.org>
|
||||
Copyright (C) 2009-2020 Michael Möller <mmoeller@openhardwaremonitor.org>
|
||||
|
||||
*/
|
||||
|
||||
@ -104,6 +104,9 @@ namespace OpenHardwareMonitor.Hardware.CPU {
|
||||
case 0x16:
|
||||
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;
|
||||
|
@ -4,7 +4,7 @@
|
||||
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) 2009-2014 Michael Möller <mmoeller@openhardwaremonitor.org>
|
||||
Copyright (C) 2009-2020 Michael Möller <mmoeller@openhardwaremonitor.org>
|
||||
|
||||
*/
|
||||
|
||||
@ -178,14 +178,20 @@ namespace OpenHardwareMonitor.Hardware.CPU {
|
||||
NextLog2(maxCoreAndThreadIdPerPackage / maxCoreIdPerPackage);
|
||||
coreMaskWith = NextLog2(maxCoreIdPerPackage);
|
||||
break;
|
||||
case Vendor.AMD:
|
||||
uint corePerPackage;
|
||||
if (maxCpuidExt >= 8)
|
||||
corePerPackage = (cpuidExtData[8, 2] & 0xFF) + 1;
|
||||
else
|
||||
corePerPackage = 1;
|
||||
threadMaskWith = 0;
|
||||
coreMaskWith = NextLog2(corePerPackage);
|
||||
case Vendor.AMD:
|
||||
if (this.family == 0x17) {
|
||||
coreMaskWith = (cpuidExtData[8, 2] >> 12) & 0xF;
|
||||
threadMaskWith =
|
||||
NextLog2(((cpuidExtData[0x1E, 1] >> 8) & 0xFF) + 1);
|
||||
} else {
|
||||
uint corePerPackage;
|
||||
if (maxCpuidExt >= 8)
|
||||
corePerPackage = (cpuidExtData[8, 2] & 0xFF) + 1;
|
||||
else
|
||||
corePerPackage = 1;
|
||||
coreMaskWith = NextLog2(corePerPackage);
|
||||
threadMaskWith = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
threadMaskWith = 0;
|
||||
|
@ -62,6 +62,7 @@
|
||||
<Compile Include="Hardware\ATI\ATIGPU.cs" />
|
||||
<Compile Include="Hardware\ATI\ATIGroup.cs" />
|
||||
<Compile Include="Hardware\Control.cs" />
|
||||
<Compile Include="Hardware\CPU\AMD17CPU.cs" />
|
||||
<Compile Include="Hardware\FirmwareTable.cs" />
|
||||
<Compile Include="Hardware\HDD\DebugSmart.cs" />
|
||||
<Compile Include="Hardware\HDD\DriveAttributeValue.cs" />
|
||||
|
Loading…
x
Reference in New Issue
Block a user