732 lines
30 KiB
C#
732 lines
30 KiB
C#
// 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 <mmoeller@openhardwaremonitor.org> and Contributors.
|
|
// All Rights Reserved.
|
|
|
|
using System;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Globalization;
|
|
using System.Text;
|
|
|
|
namespace LibreHardwareMonitor.Hardware.Cpu;
|
|
|
|
internal sealed class IntelCpu : GenericCpu
|
|
{
|
|
private readonly Sensor _busClock;
|
|
private readonly Sensor _coreAvg;
|
|
private readonly Sensor[] _coreClocks;
|
|
private readonly Sensor _coreMax;
|
|
private readonly Sensor[] _coreTemperatures;
|
|
private readonly Sensor[] _coreVIDs;
|
|
private readonly Sensor _coreVoltage;
|
|
private readonly Sensor[] _distToTjMaxTemperatures;
|
|
|
|
private readonly uint[] _energyStatusMsrs = { MSR_PKG_ENERGY_STATUS, MSR_PP0_ENERGY_STATUS, MSR_PP1_ENERGY_STATUS, MSR_DRAM_ENERGY_STATUS, MSR_PLATFORM_ENERGY_STATUS };
|
|
private readonly uint[] _lastEnergyConsumed;
|
|
private readonly DateTime[] _lastEnergyTime;
|
|
|
|
private readonly MicroArchitecture _microArchitecture;
|
|
private readonly Sensor _packageTemperature;
|
|
private readonly Sensor[] _powerSensors;
|
|
private readonly double _timeStampCounterMultiplier;
|
|
|
|
public IntelCpu(int processorIndex, CpuId[][] cpuId, ISettings settings) : base(processorIndex, cpuId, settings)
|
|
{
|
|
uint eax;
|
|
|
|
// set tjMax
|
|
float[] tjMax;
|
|
switch (_family)
|
|
{
|
|
case 0x06:
|
|
{
|
|
switch (_model)
|
|
{
|
|
case 0x0F: // Intel Core 2 (65nm)
|
|
_microArchitecture = MicroArchitecture.Core;
|
|
tjMax = _stepping switch
|
|
{
|
|
// B2
|
|
0x06 => _coreCount switch
|
|
{
|
|
2 => Floats(80 + 10),
|
|
4 => Floats(90 + 10),
|
|
_ => Floats(85 + 10)
|
|
},
|
|
// G0
|
|
0x0B => Floats(90 + 10),
|
|
// M0
|
|
0x0D => Floats(85 + 10),
|
|
_ => Floats(85 + 10)
|
|
};
|
|
break;
|
|
|
|
case 0x17: // Intel Core 2 (45nm)
|
|
_microArchitecture = MicroArchitecture.Core;
|
|
tjMax = Floats(100);
|
|
break;
|
|
|
|
case 0x1C: // Intel Atom (45nm)
|
|
_microArchitecture = MicroArchitecture.Atom;
|
|
tjMax = _stepping switch
|
|
{
|
|
// C0
|
|
0x02 => Floats(90),
|
|
// A0, B0
|
|
0x0A => Floats(100),
|
|
_ => Floats(90)
|
|
};
|
|
break;
|
|
|
|
case 0x1A: // Intel Core i7 LGA1366 (45nm)
|
|
case 0x1E: // Intel Core i5, i7 LGA1156 (45nm)
|
|
case 0x1F: // Intel Core i5, i7
|
|
case 0x25: // Intel Core i3, i5, i7 LGA1156 (32nm)
|
|
case 0x2C: // Intel Core i7 LGA1366 (32nm) 6 Core
|
|
case 0x2E: // Intel Xeon Processor 7500 series (45nm)
|
|
case 0x2F: // Intel Xeon Processor (32nm)
|
|
_microArchitecture = MicroArchitecture.Nehalem;
|
|
tjMax = GetTjMaxFromMsr();
|
|
break;
|
|
|
|
case 0x2A: // Intel Core i5, i7 2xxx LGA1155 (32nm)
|
|
case 0x2D: // Next Generation Intel Xeon, i7 3xxx LGA2011 (32nm)
|
|
_microArchitecture = MicroArchitecture.SandyBridge;
|
|
tjMax = GetTjMaxFromMsr();
|
|
break;
|
|
|
|
case 0x3A: // Intel Core i5, i7 3xxx LGA1155 (22nm)
|
|
case 0x3E: // Intel Core i7 4xxx LGA2011 (22nm)
|
|
_microArchitecture = MicroArchitecture.IvyBridge;
|
|
tjMax = GetTjMaxFromMsr();
|
|
break;
|
|
|
|
case 0x3C: // Intel Core i5, i7 4xxx LGA1150 (22nm)
|
|
case 0x3F: // Intel Xeon E5-2600/1600 v3, Core i7-59xx
|
|
// LGA2011-v3, Haswell-E (22nm)
|
|
case 0x45: // Intel Core i5, i7 4xxxU (22nm)
|
|
case 0x46:
|
|
_microArchitecture = MicroArchitecture.Haswell;
|
|
tjMax = GetTjMaxFromMsr();
|
|
break;
|
|
|
|
case 0x3D: // Intel Core M-5xxx (14nm)
|
|
case 0x47: // Intel i5, i7 5xxx, Xeon E3-1200 v4 (14nm)
|
|
case 0x4F: // Intel Xeon E5-26xx v4
|
|
case 0x56: // Intel Xeon D-15xx
|
|
_microArchitecture = MicroArchitecture.Broadwell;
|
|
tjMax = GetTjMaxFromMsr();
|
|
break;
|
|
|
|
case 0x36: // Intel Atom S1xxx, D2xxx, N2xxx (32nm)
|
|
_microArchitecture = MicroArchitecture.Atom;
|
|
tjMax = GetTjMaxFromMsr();
|
|
break;
|
|
|
|
case 0x37: // Intel Atom E3xxx, Z3xxx (22nm)
|
|
case 0x4A:
|
|
case 0x4D: // Intel Atom C2xxx (22nm)
|
|
case 0x5A:
|
|
case 0x5D:
|
|
_microArchitecture = MicroArchitecture.Silvermont;
|
|
tjMax = GetTjMaxFromMsr();
|
|
break;
|
|
|
|
case 0x4E:
|
|
case 0x5E: // Intel Core i5, i7 6xxxx LGA1151 (14nm)
|
|
case 0x55: // Intel Core X i7, i9 7xxx LGA2066 (14nm)
|
|
_microArchitecture = MicroArchitecture.Skylake;
|
|
tjMax = GetTjMaxFromMsr();
|
|
break;
|
|
|
|
case 0x4C: // Intel Airmont (Cherry Trail, Braswell)
|
|
_microArchitecture = MicroArchitecture.Airmont;
|
|
tjMax = GetTjMaxFromMsr();
|
|
break;
|
|
|
|
case 0x8E: // Intel Core i5, i7 7xxxx (14nm) (Kaby Lake) and 8xxxx (14nm++) (Coffee Lake)
|
|
case 0x9E:
|
|
_microArchitecture = MicroArchitecture.KabyLake;
|
|
tjMax = GetTjMaxFromMsr();
|
|
break;
|
|
|
|
case 0x5C: // Goldmont (Apollo Lake)
|
|
case 0x5F: // (Denverton)
|
|
_microArchitecture = MicroArchitecture.Goldmont;
|
|
tjMax = GetTjMaxFromMsr();
|
|
break;
|
|
|
|
case 0x7A: // Goldmont plus (Gemini Lake)
|
|
_microArchitecture = MicroArchitecture.GoldmontPlus;
|
|
tjMax = GetTjMaxFromMsr();
|
|
break;
|
|
|
|
case 0x66: // Intel Core i3 8xxx (10nm) (Cannon Lake)
|
|
_microArchitecture = MicroArchitecture.CannonLake;
|
|
tjMax = GetTjMaxFromMsr();
|
|
break;
|
|
|
|
case 0x7D: // Intel Core i3, i5, i7 10xxx (10nm) (Ice Lake)
|
|
case 0x7E:
|
|
case 0x6A: // Ice Lake server
|
|
case 0x6C:
|
|
_microArchitecture = MicroArchitecture.IceLake;
|
|
tjMax = GetTjMaxFromMsr();
|
|
break;
|
|
|
|
case 0xA5:
|
|
case 0xA6: // Intel Core i3, i5, i7 10xxxU (14nm)
|
|
_microArchitecture = MicroArchitecture.CometLake;
|
|
tjMax = GetTjMaxFromMsr();
|
|
break;
|
|
|
|
case 0x86: // Tremont (10nm) (Elkhart Lake, Skyhawk Lake)
|
|
_microArchitecture = MicroArchitecture.Tremont;
|
|
tjMax = GetTjMaxFromMsr();
|
|
break;
|
|
|
|
case 0x8C: // Tiger Lake (Intel 10 nm SuperFin, Gen. 11)
|
|
case 0x8D:
|
|
_microArchitecture = MicroArchitecture.TigerLake;
|
|
tjMax = GetTjMaxFromMsr();
|
|
break;
|
|
|
|
case 0x97: // Alder Lake (Intel 7 (10ESF), Gen. 12)
|
|
case 0x9A: // Alder Lake-L (Intel 7 (10ESF), Gen. 12)
|
|
case 0xBE: // Alder Lake-N (Intel 7 (10ESF), Gen. 12)
|
|
_microArchitecture = MicroArchitecture.AlderLake;
|
|
tjMax = GetTjMaxFromMsr();
|
|
break;
|
|
|
|
case 0xB7: // Raptor Lake (Intel 7 (10ESF), Gen. 13)
|
|
case 0xBA: // Raptor Lake-P (Intel 7 (10ESF), Gen. 13)
|
|
case 0xBF: // Raptor Lake-N (Intel 7 (10ESF), Gen. 13)
|
|
_microArchitecture = MicroArchitecture.RaptorLake;
|
|
tjMax = GetTjMaxFromMsr();
|
|
break;
|
|
|
|
case 0xAC: // Meteor Lake (Intel 4, TSMC N5/N6, Gen. 14)
|
|
case 0xAA: // Meteor Lake-L (Intel 4, TSMC N5/N6, Gen. 14)
|
|
_microArchitecture = MicroArchitecture.MeteorLake;
|
|
tjMax = GetTjMaxFromMsr();
|
|
break;
|
|
|
|
case 0x9C: // Jasper Lake (10nm)
|
|
_microArchitecture = MicroArchitecture.JasperLake;
|
|
tjMax = GetTjMaxFromMsr();
|
|
break;
|
|
|
|
case 0xA7: // Intel Core i5, i6, i7 11xxx (14nm) (Rocket Lake)
|
|
_microArchitecture = MicroArchitecture.RocketLake;
|
|
tjMax = GetTjMaxFromMsr();
|
|
break;
|
|
|
|
case 0xC6: // Intel Core Ultra 7 200 Series ArrowLake
|
|
_microArchitecture = MicroArchitecture.ArrowLake;
|
|
tjMax = GetTjMaxFromMsr();
|
|
break;
|
|
|
|
case 0xBD: // Intel Core Ultra 5/7 200 Series LunarLake
|
|
_microArchitecture = MicroArchitecture.LunarLake;
|
|
tjMax = GetTjMaxFromMsr();
|
|
break;
|
|
|
|
default:
|
|
_microArchitecture = MicroArchitecture.Unknown;
|
|
tjMax = Floats(100);
|
|
break;
|
|
}
|
|
}
|
|
|
|
break;
|
|
case 0x0F:
|
|
switch (_model)
|
|
{
|
|
case 0x00: // Pentium 4 (180nm)
|
|
case 0x01: // Pentium 4 (130nm)
|
|
case 0x02: // Pentium 4 (130nm)
|
|
case 0x03: // Pentium 4, Celeron D (90nm)
|
|
case 0x04: // Pentium 4, Pentium D, Celeron D (90nm)
|
|
case 0x06: // Pentium 4, Pentium D, Celeron D (65nm)
|
|
_microArchitecture = MicroArchitecture.NetBurst;
|
|
tjMax = Floats(100);
|
|
break;
|
|
|
|
default:
|
|
_microArchitecture = MicroArchitecture.Unknown;
|
|
tjMax = Floats(100);
|
|
break;
|
|
}
|
|
|
|
break;
|
|
default:
|
|
_microArchitecture = MicroArchitecture.Unknown;
|
|
tjMax = Floats(100);
|
|
break;
|
|
}
|
|
|
|
// set timeStampCounterMultiplier
|
|
switch (_microArchitecture)
|
|
{
|
|
case MicroArchitecture.Atom:
|
|
case MicroArchitecture.Core:
|
|
case MicroArchitecture.NetBurst:
|
|
if (Ring0.ReadMsr(IA32_PERF_STATUS, out uint _, out uint edx))
|
|
_timeStampCounterMultiplier = ((edx >> 8) & 0x1f) + (0.5 * ((edx >> 14) & 1));
|
|
|
|
break;
|
|
case MicroArchitecture.Airmont:
|
|
case MicroArchitecture.AlderLake:
|
|
case MicroArchitecture.ArrowLake:
|
|
case MicroArchitecture.Broadwell:
|
|
case MicroArchitecture.CannonLake:
|
|
case MicroArchitecture.CometLake:
|
|
case MicroArchitecture.Goldmont:
|
|
case MicroArchitecture.GoldmontPlus:
|
|
case MicroArchitecture.Haswell:
|
|
case MicroArchitecture.IceLake:
|
|
case MicroArchitecture.IvyBridge:
|
|
case MicroArchitecture.JasperLake:
|
|
case MicroArchitecture.KabyLake:
|
|
case MicroArchitecture.LunarLake:
|
|
case MicroArchitecture.Nehalem:
|
|
case MicroArchitecture.MeteorLake:
|
|
case MicroArchitecture.RaptorLake:
|
|
case MicroArchitecture.RocketLake:
|
|
case MicroArchitecture.SandyBridge:
|
|
case MicroArchitecture.Silvermont:
|
|
case MicroArchitecture.Skylake:
|
|
case MicroArchitecture.TigerLake:
|
|
case MicroArchitecture.Tremont:
|
|
if (Ring0.ReadMsr(MSR_PLATFORM_INFO, out eax, out uint _))
|
|
_timeStampCounterMultiplier = (eax >> 8) & 0xff;
|
|
|
|
break;
|
|
default:
|
|
_timeStampCounterMultiplier = 0;
|
|
break;
|
|
}
|
|
|
|
int coreSensorId = 0;
|
|
|
|
//core temp avg and max value
|
|
//is only available when the cpu has more than 1 core
|
|
if (cpuId[0][0].Data.GetLength(0) > 6 && (cpuId[0][0].Data[6, 0] & 0x40) != 0 && _microArchitecture != MicroArchitecture.Unknown && _coreCount > 1)
|
|
{
|
|
_coreMax = new Sensor("Core Max", coreSensorId, SensorType.Temperature, this, settings);
|
|
ActivateSensor(_coreMax);
|
|
coreSensorId++;
|
|
|
|
_coreAvg = new Sensor("Core Average", coreSensorId, SensorType.Temperature, this, settings);
|
|
ActivateSensor(_coreAvg);
|
|
coreSensorId++;
|
|
}
|
|
else
|
|
{
|
|
_coreMax = null;
|
|
_coreAvg = null;
|
|
}
|
|
|
|
// check if processor supports a digital thermal sensor at core level
|
|
if (cpuId[0][0].Data.GetLength(0) > 6 && (cpuId[0][0].Data[6, 0] & 1) != 0 && _microArchitecture != MicroArchitecture.Unknown)
|
|
{
|
|
_coreTemperatures = new Sensor[_coreCount];
|
|
for (int i = 0; i < _coreTemperatures.Length; i++)
|
|
{
|
|
_coreTemperatures[i] = new Sensor(CoreString(i),
|
|
coreSensorId,
|
|
SensorType.Temperature,
|
|
this,
|
|
new[]
|
|
{
|
|
new ParameterDescription("TjMax [°C]", "TjMax temperature of the core sensor.\n" + "Temperature = TjMax - TSlope * Value.", tjMax[i]),
|
|
new ParameterDescription("TSlope [°C]", "Temperature slope of the digital thermal sensor.\n" + "Temperature = TjMax - TSlope * Value.", 1)
|
|
},
|
|
settings);
|
|
|
|
ActivateSensor(_coreTemperatures[i]);
|
|
coreSensorId++;
|
|
}
|
|
}
|
|
else
|
|
_coreTemperatures = Array.Empty<Sensor>();
|
|
|
|
// check if processor supports a digital thermal sensor at package level
|
|
if (cpuId[0][0].Data.GetLength(0) > 6 && (cpuId[0][0].Data[6, 0] & 0x40) != 0 && _microArchitecture != MicroArchitecture.Unknown)
|
|
{
|
|
_packageTemperature = new Sensor("CPU Package",
|
|
coreSensorId,
|
|
SensorType.Temperature,
|
|
this,
|
|
new[]
|
|
{
|
|
new ParameterDescription("TjMax [°C]", "TjMax temperature of the package sensor.\n" + "Temperature = TjMax - TSlope * Value.", tjMax[0]),
|
|
new ParameterDescription("TSlope [°C]", "Temperature slope of the digital thermal sensor.\n" + "Temperature = TjMax - TSlope * Value.", 1)
|
|
},
|
|
settings);
|
|
|
|
ActivateSensor(_packageTemperature);
|
|
coreSensorId++;
|
|
}
|
|
|
|
// dist to tjmax sensor
|
|
if (cpuId[0][0].Data.GetLength(0) > 6 && (cpuId[0][0].Data[6, 0] & 1) != 0 && _microArchitecture != MicroArchitecture.Unknown)
|
|
{
|
|
_distToTjMaxTemperatures = new Sensor[_coreCount];
|
|
for (int i = 0; i < _distToTjMaxTemperatures.Length; i++)
|
|
{
|
|
_distToTjMaxTemperatures[i] = new Sensor(CoreString(i) + " Distance to TjMax", coreSensorId, SensorType.Temperature, this, settings);
|
|
ActivateSensor(_distToTjMaxTemperatures[i]);
|
|
coreSensorId++;
|
|
}
|
|
}
|
|
else
|
|
_distToTjMaxTemperatures = Array.Empty<Sensor>();
|
|
|
|
_busClock = new Sensor("Bus Speed", 0, SensorType.Clock, this, settings);
|
|
_coreClocks = new Sensor[_coreCount];
|
|
for (int i = 0; i < _coreClocks.Length; i++)
|
|
{
|
|
_coreClocks[i] = new Sensor(CoreString(i), i + 1, SensorType.Clock, this, settings);
|
|
if (HasTimeStampCounter && _microArchitecture != MicroArchitecture.Unknown)
|
|
ActivateSensor(_coreClocks[i]);
|
|
}
|
|
|
|
if (_microArchitecture is MicroArchitecture.Airmont or
|
|
MicroArchitecture.AlderLake or
|
|
MicroArchitecture.ArrowLake or
|
|
MicroArchitecture.Broadwell or
|
|
MicroArchitecture.CannonLake or
|
|
MicroArchitecture.CometLake or
|
|
MicroArchitecture.Goldmont or
|
|
MicroArchitecture.GoldmontPlus or
|
|
MicroArchitecture.Haswell or
|
|
MicroArchitecture.IceLake or
|
|
MicroArchitecture.IvyBridge or
|
|
MicroArchitecture.JasperLake or
|
|
MicroArchitecture.KabyLake or
|
|
MicroArchitecture.LunarLake or
|
|
MicroArchitecture.MeteorLake or
|
|
MicroArchitecture.RaptorLake or
|
|
MicroArchitecture.RocketLake or
|
|
MicroArchitecture.SandyBridge or
|
|
MicroArchitecture.Silvermont or
|
|
MicroArchitecture.Skylake or
|
|
MicroArchitecture.TigerLake or
|
|
MicroArchitecture.Tremont)
|
|
{
|
|
_powerSensors = new Sensor[_energyStatusMsrs.Length];
|
|
_lastEnergyTime = new DateTime[_energyStatusMsrs.Length];
|
|
_lastEnergyConsumed = new uint[_energyStatusMsrs.Length];
|
|
|
|
if (Ring0.ReadMsr(MSR_RAPL_POWER_UNIT, out eax, out uint _))
|
|
{
|
|
EnergyUnitsMultiplier = _microArchitecture switch
|
|
{
|
|
MicroArchitecture.Silvermont or MicroArchitecture.Airmont => 1.0e-6f * (1 << (int)((eax >> 8) & 0x1F)),
|
|
_ => 1.0f / (1 << (int)((eax >> 8) & 0x1F))
|
|
};
|
|
}
|
|
|
|
if (EnergyUnitsMultiplier != 0)
|
|
{
|
|
string[] powerSensorLabels = { "CPU Package", "CPU Cores", "CPU Graphics", "CPU Memory", "CPU Platform" };
|
|
|
|
for (int i = 0; i < _energyStatusMsrs.Length; i++)
|
|
{
|
|
if (!Ring0.ReadMsr(_energyStatusMsrs[i], out eax, out uint _))
|
|
continue;
|
|
|
|
// Don't show the "GPU Graphics" sensor on windows, it will show up under the GPU instead.
|
|
if (i == 2 && !Software.OperatingSystem.IsUnix)
|
|
continue;
|
|
|
|
_lastEnergyTime[i] = DateTime.UtcNow;
|
|
_lastEnergyConsumed[i] = eax;
|
|
_powerSensors[i] = new Sensor(powerSensorLabels[i],
|
|
i,
|
|
SensorType.Power,
|
|
this,
|
|
settings);
|
|
|
|
ActivateSensor(_powerSensors[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Ring0.ReadMsr(IA32_PERF_STATUS, out eax, out uint _) && ((eax >> 32) & 0xFFFF) > 0)
|
|
{
|
|
_coreVoltage = new Sensor("CPU Core", 0, SensorType.Voltage, this, settings);
|
|
ActivateSensor(_coreVoltage);
|
|
}
|
|
|
|
_coreVIDs = new Sensor[_coreCount];
|
|
for (int i = 0; i < _coreVIDs.Length; i++)
|
|
{
|
|
_coreVIDs[i] = new Sensor(CoreString(i), i + 1, SensorType.Voltage, this, settings);
|
|
ActivateSensor(_coreVIDs[i]);
|
|
}
|
|
|
|
Update();
|
|
}
|
|
|
|
public float EnergyUnitsMultiplier { get; }
|
|
|
|
private float[] Floats(float f)
|
|
{
|
|
float[] result = new float[_coreCount];
|
|
for (int i = 0; i < _coreCount; i++)
|
|
result[i] = f;
|
|
|
|
return result;
|
|
}
|
|
|
|
private float[] GetTjMaxFromMsr()
|
|
{
|
|
float[] result = new float[_coreCount];
|
|
for (int i = 0; i < _coreCount; i++)
|
|
{
|
|
if (Ring0.ReadMsr(IA32_TEMPERATURE_TARGET, out uint eax, out uint _, _cpuId[i][0].Affinity))
|
|
result[i] = (eax >> 16) & 0xFF;
|
|
else
|
|
result[i] = 100;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
protected override uint[] GetMsrs()
|
|
{
|
|
return new[]
|
|
{
|
|
MSR_PLATFORM_INFO,
|
|
IA32_PERF_STATUS,
|
|
IA32_THERM_STATUS_MSR,
|
|
IA32_TEMPERATURE_TARGET,
|
|
IA32_PACKAGE_THERM_STATUS,
|
|
MSR_RAPL_POWER_UNIT,
|
|
MSR_PKG_ENERGY_STATUS,
|
|
MSR_DRAM_ENERGY_STATUS,
|
|
MSR_PP0_ENERGY_STATUS,
|
|
MSR_PP1_ENERGY_STATUS,
|
|
MSR_PLATFORM_ENERGY_STATUS,
|
|
};
|
|
}
|
|
|
|
public override string GetReport()
|
|
{
|
|
StringBuilder r = new();
|
|
r.Append(base.GetReport());
|
|
r.Append("MicroArchitecture: ");
|
|
r.AppendLine(_microArchitecture.ToString());
|
|
r.Append("Time Stamp Counter Multiplier: ");
|
|
r.AppendLine(_timeStampCounterMultiplier.ToString(CultureInfo.InvariantCulture));
|
|
r.AppendLine();
|
|
return r.ToString();
|
|
}
|
|
|
|
public override void Update()
|
|
{
|
|
base.Update();
|
|
|
|
float coreMax = float.MinValue;
|
|
float coreAvg = 0;
|
|
uint eax;
|
|
|
|
for (int i = 0; i < _coreTemperatures.Length; i++)
|
|
{
|
|
// if reading is valid
|
|
if (Ring0.ReadMsr(IA32_THERM_STATUS_MSR, out eax, out _, _cpuId[i][0].Affinity) && (eax & 0x80000000) != 0)
|
|
{
|
|
// get the dist from tjMax from bits 22:16
|
|
float deltaT = (eax & 0x007F0000) >> 16;
|
|
float tjMax = _coreTemperatures[i].Parameters[0].Value;
|
|
float tSlope = _coreTemperatures[i].Parameters[1].Value;
|
|
_coreTemperatures[i].Value = tjMax - (tSlope * deltaT);
|
|
|
|
coreAvg += (float)_coreTemperatures[i].Value;
|
|
if (coreMax < _coreTemperatures[i].Value)
|
|
coreMax = (float)_coreTemperatures[i].Value;
|
|
|
|
_distToTjMaxTemperatures[i].Value = deltaT;
|
|
}
|
|
else
|
|
{
|
|
_coreTemperatures[i].Value = null;
|
|
_distToTjMaxTemperatures[i].Value = null;
|
|
}
|
|
}
|
|
|
|
//calculate average cpu temperature over all cores
|
|
if (_coreMax != null && coreMax != float.MinValue)
|
|
{
|
|
_coreMax.Value = coreMax;
|
|
coreAvg /= _coreTemperatures.Length;
|
|
_coreAvg.Value = coreAvg;
|
|
}
|
|
|
|
if (_packageTemperature != null)
|
|
{
|
|
// if reading is valid
|
|
if (Ring0.ReadMsr(IA32_PACKAGE_THERM_STATUS, out eax, out _, _cpuId[0][0].Affinity) && (eax & 0x80000000) != 0)
|
|
{
|
|
// get the dist from tjMax from bits 22:16
|
|
float deltaT = (eax & 0x007F0000) >> 16;
|
|
float tjMax = _packageTemperature.Parameters[0].Value;
|
|
float tSlope = _packageTemperature.Parameters[1].Value;
|
|
_packageTemperature.Value = tjMax - (tSlope * deltaT);
|
|
}
|
|
else
|
|
{
|
|
_packageTemperature.Value = null;
|
|
}
|
|
}
|
|
|
|
if (HasTimeStampCounter && _timeStampCounterMultiplier > 0)
|
|
{
|
|
double newBusClock = 0;
|
|
for (int i = 0; i < _coreClocks.Length; i++)
|
|
{
|
|
System.Threading.Thread.Sleep(1);
|
|
if (Ring0.ReadMsr(IA32_PERF_STATUS, out eax, out _, _cpuId[i][0].Affinity))
|
|
{
|
|
newBusClock = TimeStampCounterFrequency / _timeStampCounterMultiplier;
|
|
switch (_microArchitecture)
|
|
{
|
|
case MicroArchitecture.Nehalem:
|
|
_coreClocks[i].Value = (float)((eax & 0xff) * newBusClock);
|
|
break;
|
|
case MicroArchitecture.Airmont:
|
|
case MicroArchitecture.AlderLake:
|
|
case MicroArchitecture.ArrowLake:
|
|
case MicroArchitecture.Broadwell:
|
|
case MicroArchitecture.CannonLake:
|
|
case MicroArchitecture.CometLake:
|
|
case MicroArchitecture.Goldmont:
|
|
case MicroArchitecture.GoldmontPlus:
|
|
case MicroArchitecture.Haswell:
|
|
case MicroArchitecture.IceLake:
|
|
case MicroArchitecture.IvyBridge:
|
|
case MicroArchitecture.JasperLake:
|
|
case MicroArchitecture.KabyLake:
|
|
case MicroArchitecture.LunarLake:
|
|
case MicroArchitecture.MeteorLake:
|
|
case MicroArchitecture.RaptorLake:
|
|
case MicroArchitecture.RocketLake:
|
|
case MicroArchitecture.SandyBridge:
|
|
case MicroArchitecture.Silvermont:
|
|
case MicroArchitecture.Skylake:
|
|
case MicroArchitecture.TigerLake:
|
|
case MicroArchitecture.Tremont:
|
|
_coreClocks[i].Value = (float)(((eax >> 8) & 0xff) * newBusClock);
|
|
break;
|
|
default:
|
|
_coreClocks[i].Value = (float)((((eax >> 8) & 0x1f) + (0.5 * ((eax >> 14) & 1))) * newBusClock);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// if IA32_PERF_STATUS is not available, assume TSC frequency
|
|
_coreClocks[i].Value = (float)TimeStampCounterFrequency;
|
|
}
|
|
}
|
|
|
|
if (newBusClock > 0)
|
|
{
|
|
_busClock.Value = (float)newBusClock;
|
|
ActivateSensor(_busClock);
|
|
}
|
|
}
|
|
|
|
if (_powerSensors != null)
|
|
{
|
|
foreach (Sensor sensor in _powerSensors)
|
|
{
|
|
if (sensor == null)
|
|
continue;
|
|
|
|
if (!Ring0.ReadMsr(_energyStatusMsrs[sensor.Index], out eax, out _))
|
|
continue;
|
|
|
|
DateTime time = DateTime.UtcNow;
|
|
uint energyConsumed = eax;
|
|
float deltaTime = (float)(time - _lastEnergyTime[sensor.Index]).TotalSeconds;
|
|
if (deltaTime < 0.01)
|
|
continue;
|
|
|
|
sensor.Value = EnergyUnitsMultiplier * unchecked(energyConsumed - _lastEnergyConsumed[sensor.Index]) / deltaTime;
|
|
_lastEnergyTime[sensor.Index] = time;
|
|
_lastEnergyConsumed[sensor.Index] = energyConsumed;
|
|
}
|
|
}
|
|
|
|
if (_coreVoltage != null && Ring0.ReadMsr(IA32_PERF_STATUS, out _, out uint edx))
|
|
{
|
|
_coreVoltage.Value = ((edx >> 32) & 0xFFFF) / (float)(1 << 13);
|
|
}
|
|
|
|
for (int i = 0; i < _coreVIDs.Length; i++)
|
|
{
|
|
if (Ring0.ReadMsr(IA32_PERF_STATUS, out _, out edx, _cpuId[i][0].Affinity) && ((edx >> 32) & 0xFFFF) > 0)
|
|
{
|
|
_coreVIDs[i].Value = ((edx >> 32) & 0xFFFF) / (float)(1 << 13);
|
|
ActivateSensor(_coreVIDs[i]);
|
|
}
|
|
else
|
|
{
|
|
DeactivateSensor(_coreVIDs[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
[SuppressMessage("ReSharper", "IdentifierTypo")]
|
|
private enum MicroArchitecture
|
|
{
|
|
Airmont,
|
|
AlderLake,
|
|
Atom,
|
|
ArrowLake, // Gen. 15 (0xC6, -H = 0xC5)
|
|
Broadwell,
|
|
CannonLake,
|
|
CometLake,
|
|
Core,
|
|
Goldmont,
|
|
GoldmontPlus,
|
|
Haswell,
|
|
IceLake,
|
|
IvyBridge,
|
|
JasperLake,
|
|
KabyLake,
|
|
LunarLake,
|
|
Nehalem,
|
|
NetBurst,
|
|
MeteorLake,
|
|
RocketLake,
|
|
SandyBridge,
|
|
Silvermont,
|
|
Skylake,
|
|
TigerLake,
|
|
Tremont,
|
|
RaptorLake,
|
|
Unknown
|
|
}
|
|
|
|
// ReSharper disable InconsistentNaming
|
|
private const uint IA32_PACKAGE_THERM_STATUS = 0x1B1;
|
|
private const uint IA32_PERF_STATUS = 0x0198;
|
|
private const uint IA32_TEMPERATURE_TARGET = 0x01A2;
|
|
private const uint IA32_THERM_STATUS_MSR = 0x019C;
|
|
|
|
private const uint MSR_DRAM_ENERGY_STATUS = 0x619;
|
|
private const uint MSR_PKG_ENERGY_STATUS = 0x611;
|
|
private const uint MSR_PLATFORM_INFO = 0xCE;
|
|
private const uint MSR_PP0_ENERGY_STATUS = 0x639;
|
|
private const uint MSR_PP1_ENERGY_STATUS = 0x641;
|
|
private const uint MSR_PLATFORM_ENERGY_STATUS = 0x64D;
|
|
|
|
private const uint MSR_RAPL_POWER_UNIT = 0x606;
|
|
// ReSharper restore InconsistentNaming
|
|
}
|