Added support for Intel CPU power sensors (package and cores).
3 Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 The contents of this file are subject to the Mozilla Public License Version
6 1.1 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
9 http://www.mozilla.org/MPL/
11 Software distributed under the License is distributed on an "AS IS" basis,
12 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 for the specific language governing rights and limitations under the License.
15 The Original Code is the Open Hardware Monitor code.
17 The Initial Developer of the Original Code is
18 Michael Möller <m.moeller@gmx.ch>.
19 Portions created by the Initial Developer are Copyright (C) 2009-2011
20 the Initial Developer. All Rights Reserved.
24 Alternatively, the contents of this file may be used under the terms of
25 either the GNU General Public License Version 2 or later (the "GPL"), or
26 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 in which case the provisions of the GPL or the LGPL are applicable instead
28 of those above. If you wish to allow use of your version of this file only
29 under the terms of either the GPL or the LGPL, and not to allow others to
30 use your version of this file under the terms of the MPL, indicate your
31 decision by deleting the provisions above and replace them with the notice
32 and other provisions required by the GPL or the LGPL. If you do not delete
33 the provisions above, a recipient may use your version of this file under
34 the terms of any one of the MPL, the GPL or the LGPL.
39 using System.Globalization;
42 namespace OpenHardwareMonitor.Hardware.CPU {
43 internal sealed class IntelCPU : GenericCPU {
45 private enum Microarchitecture {
54 private readonly Sensor[] coreTemperatures;
55 private readonly Sensor packageTemperature;
56 private readonly Sensor[] coreClocks;
57 private readonly Sensor busClock;
58 private readonly Sensor packagePower;
59 private readonly Sensor coresPower;
61 private readonly Microarchitecture microarchitecture;
62 private readonly double timeStampCounterMultiplier;
64 private const uint IA32_THERM_STATUS_MSR = 0x019C;
65 private const uint IA32_TEMPERATURE_TARGET = 0x01A2;
66 private const uint IA32_PERF_STATUS = 0x0198;
67 private const uint MSR_PLATFORM_INFO = 0xCE;
68 private const uint IA32_PACKAGE_THERM_STATUS = 0x1B1;
69 private const uint MSR_RAPL_POWER_UNIT = 0x606;
70 private const uint MSR_PKG_ENERY_STATUS = 0x611;
71 private const uint MSR_PP0_ENERY_STATUS = 0x639;
73 private float energyUnitMultiplier = 0;
74 private DateTime lastPackageTime;
75 private uint lastPackageEnergyConsumed;
76 private DateTime lastCoresTime;
77 private uint lastCoresEnergyConsumed;
81 private float[] Floats(float f) {
82 float[] result = new float[coreCount];
83 for (int i = 0; i < coreCount; i++)
88 private float[] GetTjMaxFromMSR() {
90 float[] result = new float[coreCount];
91 for (int i = 0; i < coreCount; i++) {
92 if (Ring0.RdmsrTx(IA32_TEMPERATURE_TARGET, out eax,
93 out edx, 1UL << cpuid[i][0].Thread)) {
94 result[i] = (eax >> 16) & 0xFF;
102 public IntelCPU(int processorIndex, CPUID[][] cpuid, ISettings settings)
103 : base(processorIndex, cpuid, settings)
110 case 0x0F: // Intel Core 2 (65nm)
111 microarchitecture = Microarchitecture.Core;
116 tjMax = Floats(80 + 10); break;
118 tjMax = Floats(90 + 10); break;
120 tjMax = Floats(85 + 10); break;
122 tjMax = Floats(80 + 10); break;
124 tjMax = Floats(90 + 10); break;
126 tjMax = Floats(85 + 10); break;
128 tjMax = Floats(85 + 10); break;
130 case 0x17: // Intel Core 2 (45nm)
131 microarchitecture = Microarchitecture.Core;
132 tjMax = Floats(100); break;
133 case 0x1C: // Intel Atom (45nm)
134 microarchitecture = Microarchitecture.Atom;
137 tjMax = Floats(90); break;
139 tjMax = Floats(100); break;
141 tjMax = Floats(90); break;
143 case 0x1A: // Intel Core i7 LGA1366 (45nm)
144 case 0x1E: // Intel Core i5, i7 LGA1156 (45nm)
145 case 0x1F: // Intel Core i5, i7
146 case 0x25: // Intel Core i3, i5, i7 LGA1156 (32nm)
147 case 0x2C: // Intel Core i7 LGA1366 (32nm) 6 Core
148 case 0x2E: // Intel Xeon Processor 7500 series
149 microarchitecture = Microarchitecture.Nehalem;
150 tjMax = GetTjMaxFromMSR();
152 case 0x2A: // Intel Core i5, i7 2xxx LGA1155 (32nm)
153 case 0x2D: // Next Generation Intel Xeon Processor
154 microarchitecture = Microarchitecture.SandyBridge;
155 tjMax = GetTjMaxFromMSR();
158 microarchitecture = Microarchitecture.Unknown;
165 case 0x00: // Pentium 4 (180nm)
166 case 0x01: // Pentium 4 (130nm)
167 case 0x02: // Pentium 4 (130nm)
168 case 0x03: // Pentium 4, Celeron D (90nm)
169 case 0x04: // Pentium 4, Pentium D, Celeron D (90nm)
170 case 0x06: // Pentium 4, Pentium D, Celeron D (65nm)
171 microarchitecture = Microarchitecture.NetBurst;
175 microarchitecture = Microarchitecture.Unknown;
181 microarchitecture = Microarchitecture.Unknown;
186 // set timeStampCounterMultiplier
187 switch (microarchitecture) {
188 case Microarchitecture.NetBurst:
189 case Microarchitecture.Atom:
190 case Microarchitecture.Core: {
192 if (Ring0.Rdmsr(IA32_PERF_STATUS, out eax, out edx)) {
193 timeStampCounterMultiplier =
194 ((edx >> 8) & 0x1f) + 0.5 * ((edx >> 14) & 1);
197 case Microarchitecture.Nehalem:
198 case Microarchitecture.SandyBridge: {
200 if (Ring0.Rdmsr(MSR_PLATFORM_INFO, out eax, out edx)) {
201 timeStampCounterMultiplier = (eax >> 8) & 0xff;
205 timeStampCounterMultiplier = 1;
207 if (Ring0.Rdmsr(IA32_PERF_STATUS, out eax, out edx)) {
208 timeStampCounterMultiplier =
209 ((edx >> 8) & 0x1f) + 0.5 * ((edx >> 14) & 1);
214 // check if processor supports a digital thermal sensor at core level
215 if (cpuid[0][0].Data.GetLength(0) > 6 &&
216 (cpuid[0][0].Data[6, 0] & 1) != 0)
218 coreTemperatures = new Sensor[coreCount];
219 for (int i = 0; i < coreTemperatures.Length; i++) {
220 coreTemperatures[i] = new Sensor(CoreString(i), i,
221 SensorType.Temperature, this, new [] {
222 new ParameterDescription(
223 "TjMax [°C]", "TjMax temperature of the core sensor.\n" +
224 "Temperature = TjMax - TSlope * Value.", tjMax[i]),
225 new ParameterDescription("TSlope [°C]",
226 "Temperature slope of the digital thermal sensor.\n" +
227 "Temperature = TjMax - TSlope * Value.", 1)}, settings);
228 ActivateSensor(coreTemperatures[i]);
231 coreTemperatures = new Sensor[0];
234 // check if processor supports a digital thermal sensor at package level
235 if (cpuid[0][0].Data.GetLength(0) > 6 &&
236 (cpuid[0][0].Data[6, 0] & 0x40) != 0)
238 packageTemperature = new Sensor("CPU Package",
239 coreTemperatures.Length, SensorType.Temperature, this, new[] {
240 new ParameterDescription(
241 "TjMax [°C]", "TjMax temperature of the package sensor.\n" +
242 "Temperature = TjMax - TSlope * Value.", tjMax[0]),
243 new ParameterDescription("TSlope [°C]",
244 "Temperature slope of the digital thermal sensor.\n" +
245 "Temperature = TjMax - TSlope * Value.", 1)}, settings);
246 ActivateSensor(packageTemperature);
249 busClock = new Sensor("Bus Speed", 0, SensorType.Clock, this, settings);
250 coreClocks = new Sensor[coreCount];
251 for (int i = 0; i < coreClocks.Length; i++) {
253 new Sensor(CoreString(i), i + 1, SensorType.Clock, this, settings);
254 if (HasTimeStampCounter)
255 ActivateSensor(coreClocks[i]);
258 if (microarchitecture == Microarchitecture.SandyBridge) {
260 if (Ring0.Rdmsr(MSR_RAPL_POWER_UNIT, out eax, out edx))
261 energyUnitMultiplier = 1.0f / (1 << (int)((eax >> 8) & 0x1FF));
264 if (energyUnitMultiplier != 0 &&
265 Ring0.Rdmsr(MSR_PKG_ENERY_STATUS, out eax, out edx))
267 lastPackageTime = DateTime.UtcNow;
268 lastPackageEnergyConsumed = eax;
269 packagePower = new Sensor("CPU Package", 0, SensorType.Power, this,
271 ActivateSensor(packagePower);
274 if (energyUnitMultiplier != 0 &&
275 Ring0.Rdmsr(MSR_PP0_ENERY_STATUS, out eax, out edx))
277 lastCoresTime = DateTime.UtcNow;
278 lastCoresEnergyConsumed = eax;
279 coresPower = new Sensor("CPU Cores", 1, SensorType.Power, this,
281 ActivateSensor(coresPower);
288 protected override uint[] GetMSRs() {
292 IA32_THERM_STATUS_MSR,
293 IA32_TEMPERATURE_TARGET,
294 IA32_PACKAGE_THERM_STATUS,
296 MSR_PKG_ENERY_STATUS,
301 public override string GetReport() {
302 StringBuilder r = new StringBuilder();
303 r.Append(base.GetReport());
305 r.Append("Microarchitecture: ");
306 r.AppendLine(microarchitecture.ToString());
307 r.Append("Time Stamp Counter Multiplier: ");
308 r.AppendLine(timeStampCounterMultiplier.ToString(
309 CultureInfo.InvariantCulture));
315 public override void Update() {
318 for (int i = 0; i < coreTemperatures.Length; i++) {
321 IA32_THERM_STATUS_MSR, out eax, out edx,
322 1UL << cpuid[i][0].Thread)) {
323 // if reading is valid
324 if ((eax & 0x80000000) != 0) {
325 // get the dist from tjMax from bits 22:16
326 float deltaT = ((eax & 0x007F0000) >> 16);
327 float tjMax = coreTemperatures[i].Parameters[0].Value;
328 float tSlope = coreTemperatures[i].Parameters[1].Value;
329 coreTemperatures[i].Value = tjMax - tSlope * deltaT;
331 coreTemperatures[i].Value = null;
336 if (packageTemperature != null) {
339 IA32_PACKAGE_THERM_STATUS, out eax, out edx,
340 1UL << cpuid[0][0].Thread)) {
341 // get the dist from tjMax from bits 22:16
342 float deltaT = ((eax & 0x007F0000) >> 16);
343 float tjMax = packageTemperature.Parameters[0].Value;
344 float tSlope = packageTemperature.Parameters[1].Value;
345 packageTemperature.Value = tjMax - tSlope * deltaT;
347 packageTemperature.Value = null;
351 if (HasTimeStampCounter) {
352 double newBusClock = 0;
354 for (int i = 0; i < coreClocks.Length; i++) {
355 System.Threading.Thread.Sleep(1);
356 if (Ring0.RdmsrTx(IA32_PERF_STATUS, out eax, out edx,
357 1UL << cpuid[i][0].Thread))
360 TimeStampCounterFrequency / timeStampCounterMultiplier;
361 switch (microarchitecture) {
362 case Microarchitecture.Nehalem: {
363 uint multiplier = eax & 0xff;
364 coreClocks[i].Value = (float)(multiplier * newBusClock);
366 case Microarchitecture.SandyBridge: {
367 uint multiplier = (eax >> 8) & 0xff;
368 coreClocks[i].Value = (float)(multiplier * newBusClock);
372 ((eax >> 8) & 0x1f) + 0.5 * ((eax >> 14) & 1);
373 coreClocks[i].Value = (float)(multiplier * newBusClock);
377 // if IA32_PERF_STATUS is not available, assume TSC frequency
378 coreClocks[i].Value = (float)TimeStampCounterFrequency;
381 if (newBusClock > 0) {
382 this.busClock.Value = (float)newBusClock;
383 ActivateSensor(this.busClock);
388 if (packagePower != null) {
390 if (Ring0.Rdmsr(MSR_PKG_ENERY_STATUS, out eax, out edx)) {
391 DateTime time = DateTime.UtcNow;
392 uint energyConsumed = eax;
393 float deltaTime = (float)(time - lastPackageTime).TotalSeconds;
394 if (deltaTime > 0.01) {
395 packagePower.Value = energyUnitMultiplier *
396 unchecked(energyConsumed - lastPackageEnergyConsumed) / deltaTime;
397 lastPackageTime = time;
398 lastPackageEnergyConsumed = energyConsumed;
403 if (coresPower != null) {
405 if (Ring0.Rdmsr(MSR_PP0_ENERY_STATUS, out eax, out edx)) {
406 DateTime time = DateTime.UtcNow;
407 uint energyConsumed = eax;
408 float deltaTime = (float)(time - lastCoresTime).TotalSeconds;
409 if (deltaTime > 0.01) {
410 coresPower.Value = energyUnitMultiplier *
411 unchecked(energyConsumed - lastCoresEnergyConsumed) / deltaTime;
412 lastCoresTime = time;
413 lastCoresEnergyConsumed = energyConsumed;