Fixed Issue 651.
3 This Source Code Form is subject to the terms of the Mozilla Public
4 License, v. 2.0. If a copy of the MPL was not distributed with this
5 file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 Copyright (C) 2009-2014 Michael Möller <mmoeller@openhardwaremonitor.org>
12 using System.Globalization;
15 namespace OpenHardwareMonitor.Hardware.CPU {
16 internal sealed class IntelCPU : GenericCPU {
18 private enum Microarchitecture {
31 private readonly Sensor[] coreTemperatures;
32 private readonly Sensor packageTemperature;
33 private readonly Sensor[] coreClocks;
34 private readonly Sensor busClock;
35 private readonly Sensor[] powerSensors;
37 private readonly Microarchitecture microarchitecture;
38 private readonly double timeStampCounterMultiplier;
40 private const uint IA32_THERM_STATUS_MSR = 0x019C;
41 private const uint IA32_TEMPERATURE_TARGET = 0x01A2;
42 private const uint IA32_PERF_STATUS = 0x0198;
43 private const uint MSR_PLATFORM_INFO = 0xCE;
44 private const uint IA32_PACKAGE_THERM_STATUS = 0x1B1;
45 private const uint MSR_RAPL_POWER_UNIT = 0x606;
46 private const uint MSR_PKG_ENERY_STATUS = 0x611;
47 private const uint MSR_DRAM_ENERGY_STATUS = 0x619;
48 private const uint MSR_PP0_ENERY_STATUS = 0x639;
49 private const uint MSR_PP1_ENERY_STATUS = 0x641;
51 private readonly uint[] energyStatusMSRs = { MSR_PKG_ENERY_STATUS,
52 MSR_PP0_ENERY_STATUS, MSR_PP1_ENERY_STATUS, MSR_DRAM_ENERGY_STATUS };
53 private readonly string[] powerSensorLabels =
54 { "CPU Package", "CPU Cores", "CPU Graphics", "CPU DRAM" };
55 private float energyUnitMultiplier = 0;
56 private DateTime[] lastEnergyTime;
57 private uint[] lastEnergyConsumed;
60 private float[] Floats(float f) {
61 float[] result = new float[coreCount];
62 for (int i = 0; i < coreCount; i++)
67 private float[] GetTjMaxFromMSR() {
69 float[] result = new float[coreCount];
70 for (int i = 0; i < coreCount; i++) {
71 if (Ring0.RdmsrTx(IA32_TEMPERATURE_TARGET, out eax,
72 out edx, 1UL << cpuid[i][0].Thread)) {
73 result[i] = (eax >> 16) & 0xFF;
81 public IntelCPU(int processorIndex, CPUID[][] cpuid, ISettings settings)
82 : base(processorIndex, cpuid, settings) {
88 case 0x0F: // Intel Core 2 (65nm)
89 microarchitecture = Microarchitecture.Core;
94 tjMax = Floats(80 + 10); break;
96 tjMax = Floats(90 + 10); break;
98 tjMax = Floats(85 + 10); break;
100 tjMax = Floats(80 + 10); break;
102 tjMax = Floats(90 + 10); break;
104 tjMax = Floats(85 + 10); break;
106 tjMax = Floats(85 + 10); break;
108 case 0x17: // Intel Core 2 (45nm)
109 microarchitecture = Microarchitecture.Core;
110 tjMax = Floats(100); break;
111 case 0x1C: // Intel Atom (45nm)
112 microarchitecture = Microarchitecture.Atom;
115 tjMax = Floats(90); break;
117 tjMax = Floats(100); break;
119 tjMax = Floats(90); break;
121 case 0x1A: // Intel Core i7 LGA1366 (45nm)
122 case 0x1E: // Intel Core i5, i7 LGA1156 (45nm)
123 case 0x1F: // Intel Core i5, i7
124 case 0x25: // Intel Core i3, i5, i7 LGA1156 (32nm)
125 case 0x2C: // Intel Core i7 LGA1366 (32nm) 6 Core
126 case 0x2E: // Intel Xeon Processor 7500 series (45nm)
127 case 0x2F: // Intel Xeon Processor (32nm)
128 microarchitecture = Microarchitecture.Nehalem;
129 tjMax = GetTjMaxFromMSR();
131 case 0x2A: // Intel Core i5, i7 2xxx LGA1155 (32nm)
132 case 0x2D: // Next Generation Intel Xeon, i7 3xxx LGA2011 (32nm)
133 microarchitecture = Microarchitecture.SandyBridge;
134 tjMax = GetTjMaxFromMSR();
136 case 0x3A: // Intel Core i5, i7 3xxx LGA1155 (22nm)
137 case 0x3E: // Intel Core i7 4xxx LGA2011 (22nm)
138 microarchitecture = Microarchitecture.IvyBridge;
139 tjMax = GetTjMaxFromMSR();
141 case 0x3C: // Intel Core i5, i7 4xxx LGA1150 (22nm)
142 case 0x3F: // Intel Xeon E5-2600/1600 v3, Core i7-59xx
143 // LGA2011-v3, Haswell-E (22nm)
144 case 0x45: // Intel Core i5, i7 4xxxU (22nm)
146 microarchitecture = Microarchitecture.Haswell;
147 tjMax = GetTjMaxFromMSR();
149 case 0x3D: // Intel Core M-5xxx (14nm)
150 microarchitecture = Microarchitecture.Broadwell;
151 tjMax = GetTjMaxFromMSR();
153 case 0x36: // Intel Atom S1xxx, D2xxx, N2xxx (32nm)
154 microarchitecture = Microarchitecture.Atom;
155 tjMax = GetTjMaxFromMSR();
157 case 0x37: // Intel Atom E3xxx, Z3xxx (22nm)
159 case 0x4D: // Intel Atom C2xxx (22nm)
162 microarchitecture = Microarchitecture.Silvermont;
163 tjMax = GetTjMaxFromMSR();
166 microarchitecture = Microarchitecture.Unknown;
173 case 0x00: // Pentium 4 (180nm)
174 case 0x01: // Pentium 4 (130nm)
175 case 0x02: // Pentium 4 (130nm)
176 case 0x03: // Pentium 4, Celeron D (90nm)
177 case 0x04: // Pentium 4, Pentium D, Celeron D (90nm)
178 case 0x06: // Pentium 4, Pentium D, Celeron D (65nm)
179 microarchitecture = Microarchitecture.NetBurst;
183 microarchitecture = Microarchitecture.Unknown;
189 microarchitecture = Microarchitecture.Unknown;
194 // set timeStampCounterMultiplier
195 switch (microarchitecture) {
196 case Microarchitecture.NetBurst:
197 case Microarchitecture.Atom:
198 case Microarchitecture.Core: {
200 if (Ring0.Rdmsr(IA32_PERF_STATUS, out eax, out edx)) {
201 timeStampCounterMultiplier =
202 ((edx >> 8) & 0x1f) + 0.5 * ((edx >> 14) & 1);
205 case Microarchitecture.Nehalem:
206 case Microarchitecture.SandyBridge:
207 case Microarchitecture.IvyBridge:
208 case Microarchitecture.Haswell:
209 case Microarchitecture.Broadwell:
210 case Microarchitecture.Silvermont: {
212 if (Ring0.Rdmsr(MSR_PLATFORM_INFO, out eax, out edx)) {
213 timeStampCounterMultiplier = (eax >> 8) & 0xff;
217 timeStampCounterMultiplier = 0;
221 // check if processor supports a digital thermal sensor at core level
222 if (cpuid[0][0].Data.GetLength(0) > 6 &&
223 (cpuid[0][0].Data[6, 0] & 1) != 0 &&
224 microarchitecture != Microarchitecture.Unknown)
226 coreTemperatures = new Sensor[coreCount];
227 for (int i = 0; i < coreTemperatures.Length; i++) {
228 coreTemperatures[i] = new Sensor(CoreString(i), i,
229 SensorType.Temperature, this, new[] {
230 new ParameterDescription(
231 "TjMax [°C]", "TjMax temperature of the core sensor.\n" +
232 "Temperature = TjMax - TSlope * Value.", tjMax[i]),
233 new ParameterDescription("TSlope [°C]",
234 "Temperature slope of the digital thermal sensor.\n" +
235 "Temperature = TjMax - TSlope * Value.", 1)}, settings);
236 ActivateSensor(coreTemperatures[i]);
239 coreTemperatures = new Sensor[0];
242 // check if processor supports a digital thermal sensor at package level
243 if (cpuid[0][0].Data.GetLength(0) > 6 &&
244 (cpuid[0][0].Data[6, 0] & 0x40) != 0 &&
245 microarchitecture != Microarchitecture.Unknown)
247 packageTemperature = new Sensor("CPU Package",
248 coreTemperatures.Length, SensorType.Temperature, this, new[] {
249 new ParameterDescription(
250 "TjMax [°C]", "TjMax temperature of the package sensor.\n" +
251 "Temperature = TjMax - TSlope * Value.", tjMax[0]),
252 new ParameterDescription("TSlope [°C]",
253 "Temperature slope of the digital thermal sensor.\n" +
254 "Temperature = TjMax - TSlope * Value.", 1)}, settings);
255 ActivateSensor(packageTemperature);
258 busClock = new Sensor("Bus Speed", 0, SensorType.Clock, this, settings);
259 coreClocks = new Sensor[coreCount];
260 for (int i = 0; i < coreClocks.Length; i++) {
262 new Sensor(CoreString(i), i + 1, SensorType.Clock, this, settings);
263 if (HasTimeStampCounter && microarchitecture != Microarchitecture.Unknown)
264 ActivateSensor(coreClocks[i]);
267 if (microarchitecture == Microarchitecture.SandyBridge ||
268 microarchitecture == Microarchitecture.IvyBridge ||
269 microarchitecture == Microarchitecture.Haswell ||
270 microarchitecture == Microarchitecture.Broadwell ||
271 microarchitecture == Microarchitecture.Silvermont)
273 powerSensors = new Sensor[energyStatusMSRs.Length];
274 lastEnergyTime = new DateTime[energyStatusMSRs.Length];
275 lastEnergyConsumed = new uint[energyStatusMSRs.Length];
278 if (Ring0.Rdmsr(MSR_RAPL_POWER_UNIT, out eax, out edx))
279 switch (microarchitecture) {
280 case Microarchitecture.Silvermont:
281 energyUnitMultiplier = 1.0e-6f * (1 << (int)((eax >> 8) & 0x1F));
284 energyUnitMultiplier = 1.0f / (1 << (int)((eax >> 8) & 0x1F));
287 if (energyUnitMultiplier != 0) {
288 for (int i = 0; i < energyStatusMSRs.Length; i++) {
289 if (!Ring0.Rdmsr(energyStatusMSRs[i], out eax, out edx))
292 lastEnergyTime[i] = DateTime.UtcNow;
293 lastEnergyConsumed[i] = eax;
294 powerSensors[i] = new Sensor(powerSensorLabels[i], i,
295 SensorType.Power, this, settings);
296 ActivateSensor(powerSensors[i]);
304 protected override uint[] GetMSRs() {
308 IA32_THERM_STATUS_MSR,
309 IA32_TEMPERATURE_TARGET,
310 IA32_PACKAGE_THERM_STATUS,
312 MSR_PKG_ENERY_STATUS,
313 MSR_DRAM_ENERGY_STATUS,
314 MSR_PP0_ENERY_STATUS,
319 public override string GetReport() {
320 StringBuilder r = new StringBuilder();
321 r.Append(base.GetReport());
323 r.Append("Microarchitecture: ");
324 r.AppendLine(microarchitecture.ToString());
325 r.Append("Time Stamp Counter Multiplier: ");
326 r.AppendLine(timeStampCounterMultiplier.ToString(
327 CultureInfo.InvariantCulture));
333 public override void Update() {
336 for (int i = 0; i < coreTemperatures.Length; i++) {
338 // if reading is valid
339 if (Ring0.RdmsrTx(IA32_THERM_STATUS_MSR, out eax, out edx,
340 1UL << cpuid[i][0].Thread) && (eax & 0x80000000) != 0)
342 // get the dist from tjMax from bits 22:16
343 float deltaT = ((eax & 0x007F0000) >> 16);
344 float tjMax = coreTemperatures[i].Parameters[0].Value;
345 float tSlope = coreTemperatures[i].Parameters[1].Value;
346 coreTemperatures[i].Value = tjMax - tSlope * deltaT;
348 coreTemperatures[i].Value = null;
352 if (packageTemperature != null) {
354 // if reading is valid
355 if (Ring0.RdmsrTx(IA32_PACKAGE_THERM_STATUS, out eax, out edx,
356 1UL << cpuid[0][0].Thread) && (eax & 0x80000000) != 0)
358 // get the dist from tjMax from bits 22:16
359 float deltaT = ((eax & 0x007F0000) >> 16);
360 float tjMax = packageTemperature.Parameters[0].Value;
361 float tSlope = packageTemperature.Parameters[1].Value;
362 packageTemperature.Value = tjMax - tSlope * deltaT;
364 packageTemperature.Value = null;
368 if (HasTimeStampCounter && timeStampCounterMultiplier > 0) {
369 double newBusClock = 0;
371 for (int i = 0; i < coreClocks.Length; i++) {
372 System.Threading.Thread.Sleep(1);
373 if (Ring0.RdmsrTx(IA32_PERF_STATUS, out eax, out edx,
374 1UL << cpuid[i][0].Thread)) {
376 TimeStampCounterFrequency / timeStampCounterMultiplier;
377 switch (microarchitecture) {
378 case Microarchitecture.Nehalem: {
379 uint multiplier = eax & 0xff;
380 coreClocks[i].Value = (float)(multiplier * newBusClock);
382 case Microarchitecture.SandyBridge:
383 case Microarchitecture.IvyBridge:
384 case Microarchitecture.Haswell:
385 case Microarchitecture.Broadwell:
386 case Microarchitecture.Silvermont: {
387 uint multiplier = (eax >> 8) & 0xff;
388 coreClocks[i].Value = (float)(multiplier * newBusClock);
392 ((eax >> 8) & 0x1f) + 0.5 * ((eax >> 14) & 1);
393 coreClocks[i].Value = (float)(multiplier * newBusClock);
397 // if IA32_PERF_STATUS is not available, assume TSC frequency
398 coreClocks[i].Value = (float)TimeStampCounterFrequency;
401 if (newBusClock > 0) {
402 this.busClock.Value = (float)newBusClock;
403 ActivateSensor(this.busClock);
407 if (powerSensors != null) {
408 foreach (Sensor sensor in powerSensors) {
413 if (!Ring0.Rdmsr(energyStatusMSRs[sensor.Index], out eax, out edx))
416 DateTime time = DateTime.UtcNow;
417 uint energyConsumed = eax;
419 (float)(time - lastEnergyTime[sensor.Index]).TotalSeconds;
420 if (deltaTime < 0.01)
423 sensor.Value = energyUnitMultiplier * unchecked(
424 energyConsumed - lastEnergyConsumed[sensor.Index]) / deltaTime;
425 lastEnergyTime[sensor.Index] = time;
426 lastEnergyConsumed[sensor.Index] = energyConsumed;