Changed the license to the Mozilla Public License 2.0 and update the licensing information.
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-2011 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 {
27 private readonly Sensor[] coreTemperatures;
28 private readonly Sensor packageTemperature;
29 private readonly Sensor[] coreClocks;
30 private readonly Sensor busClock;
31 private readonly Sensor[] powerSensors;
33 private readonly Microarchitecture microarchitecture;
34 private readonly double timeStampCounterMultiplier;
36 private const uint IA32_THERM_STATUS_MSR = 0x019C;
37 private const uint IA32_TEMPERATURE_TARGET = 0x01A2;
38 private const uint IA32_PERF_STATUS = 0x0198;
39 private const uint MSR_PLATFORM_INFO = 0xCE;
40 private const uint IA32_PACKAGE_THERM_STATUS = 0x1B1;
41 private const uint MSR_RAPL_POWER_UNIT = 0x606;
42 private const uint MSR_PKG_ENERY_STATUS = 0x611;
43 private const uint MSR_DRAM_ENERGY_STATUS = 0x619;
44 private const uint MSR_PP0_ENERY_STATUS = 0x639;
45 private const uint MSR_PP1_ENERY_STATUS = 0x641;
47 private readonly uint[] energyStatusMSRs = { MSR_PKG_ENERY_STATUS,
48 MSR_PP0_ENERY_STATUS, MSR_PP1_ENERY_STATUS, MSR_DRAM_ENERGY_STATUS };
49 private readonly string[] powerSensorLabels =
50 { "CPU Package", "CPU Cores", "CPU Graphics", "CPU DRAM" };
51 private float energyUnitMultiplier = 0;
52 private DateTime[] lastEnergyTime;
53 private uint[] lastEnergyConsumed;
56 private float[] Floats(float f) {
57 float[] result = new float[coreCount];
58 for (int i = 0; i < coreCount; i++)
63 private float[] GetTjMaxFromMSR() {
65 float[] result = new float[coreCount];
66 for (int i = 0; i < coreCount; i++) {
67 if (Ring0.RdmsrTx(IA32_TEMPERATURE_TARGET, out eax,
68 out edx, 1UL << cpuid[i][0].Thread)) {
69 result[i] = (eax >> 16) & 0xFF;
77 public IntelCPU(int processorIndex, CPUID[][] cpuid, ISettings settings)
78 : base(processorIndex, cpuid, settings) {
84 case 0x0F: // Intel Core 2 (65nm)
85 microarchitecture = Microarchitecture.Core;
90 tjMax = Floats(80 + 10); break;
92 tjMax = Floats(90 + 10); break;
94 tjMax = Floats(85 + 10); break;
96 tjMax = Floats(80 + 10); break;
98 tjMax = Floats(90 + 10); break;
100 tjMax = Floats(85 + 10); break;
102 tjMax = Floats(85 + 10); break;
104 case 0x17: // Intel Core 2 (45nm)
105 microarchitecture = Microarchitecture.Core;
106 tjMax = Floats(100); break;
107 case 0x1C: // Intel Atom (45nm)
108 microarchitecture = Microarchitecture.Atom;
111 tjMax = Floats(90); break;
113 tjMax = Floats(100); break;
115 tjMax = Floats(90); break;
117 case 0x1A: // Intel Core i7 LGA1366 (45nm)
118 case 0x1E: // Intel Core i5, i7 LGA1156 (45nm)
119 case 0x1F: // Intel Core i5, i7
120 case 0x25: // Intel Core i3, i5, i7 LGA1156 (32nm)
121 case 0x2C: // Intel Core i7 LGA1366 (32nm) 6 Core
122 case 0x2E: // Intel Xeon Processor 7500 series
123 microarchitecture = Microarchitecture.Nehalem;
124 tjMax = GetTjMaxFromMSR();
126 case 0x2A: // Intel Core i5, i7 2xxx LGA1155 (32nm)
127 case 0x2D: // Next Generation Intel Xeon Processor
128 microarchitecture = Microarchitecture.SandyBridge;
129 tjMax = GetTjMaxFromMSR();
132 microarchitecture = Microarchitecture.Unknown;
139 case 0x00: // Pentium 4 (180nm)
140 case 0x01: // Pentium 4 (130nm)
141 case 0x02: // Pentium 4 (130nm)
142 case 0x03: // Pentium 4, Celeron D (90nm)
143 case 0x04: // Pentium 4, Pentium D, Celeron D (90nm)
144 case 0x06: // Pentium 4, Pentium D, Celeron D (65nm)
145 microarchitecture = Microarchitecture.NetBurst;
149 microarchitecture = Microarchitecture.Unknown;
155 microarchitecture = Microarchitecture.Unknown;
160 // set timeStampCounterMultiplier
161 switch (microarchitecture) {
162 case Microarchitecture.NetBurst:
163 case Microarchitecture.Atom:
164 case Microarchitecture.Core: {
166 if (Ring0.Rdmsr(IA32_PERF_STATUS, out eax, out edx)) {
167 timeStampCounterMultiplier =
168 ((edx >> 8) & 0x1f) + 0.5 * ((edx >> 14) & 1);
171 case Microarchitecture.Nehalem:
172 case Microarchitecture.SandyBridge: {
174 if (Ring0.Rdmsr(MSR_PLATFORM_INFO, out eax, out edx)) {
175 timeStampCounterMultiplier = (eax >> 8) & 0xff;
179 timeStampCounterMultiplier = 1;
181 if (Ring0.Rdmsr(IA32_PERF_STATUS, out eax, out edx)) {
182 timeStampCounterMultiplier =
183 ((edx >> 8) & 0x1f) + 0.5 * ((edx >> 14) & 1);
188 // check if processor supports a digital thermal sensor at core level
189 if (cpuid[0][0].Data.GetLength(0) > 6 &&
190 (cpuid[0][0].Data[6, 0] & 1) != 0) {
191 coreTemperatures = new Sensor[coreCount];
192 for (int i = 0; i < coreTemperatures.Length; i++) {
193 coreTemperatures[i] = new Sensor(CoreString(i), i,
194 SensorType.Temperature, this, new[] {
195 new ParameterDescription(
196 "TjMax [°C]", "TjMax temperature of the core sensor.\n" +
197 "Temperature = TjMax - TSlope * Value.", tjMax[i]),
198 new ParameterDescription("TSlope [°C]",
199 "Temperature slope of the digital thermal sensor.\n" +
200 "Temperature = TjMax - TSlope * Value.", 1)}, settings);
201 ActivateSensor(coreTemperatures[i]);
204 coreTemperatures = new Sensor[0];
207 // check if processor supports a digital thermal sensor at package level
208 if (cpuid[0][0].Data.GetLength(0) > 6 &&
209 (cpuid[0][0].Data[6, 0] & 0x40) != 0) {
210 packageTemperature = new Sensor("CPU Package",
211 coreTemperatures.Length, SensorType.Temperature, this, new[] {
212 new ParameterDescription(
213 "TjMax [°C]", "TjMax temperature of the package sensor.\n" +
214 "Temperature = TjMax - TSlope * Value.", tjMax[0]),
215 new ParameterDescription("TSlope [°C]",
216 "Temperature slope of the digital thermal sensor.\n" +
217 "Temperature = TjMax - TSlope * Value.", 1)}, settings);
218 ActivateSensor(packageTemperature);
221 busClock = new Sensor("Bus Speed", 0, SensorType.Clock, this, settings);
222 coreClocks = new Sensor[coreCount];
223 for (int i = 0; i < coreClocks.Length; i++) {
225 new Sensor(CoreString(i), i + 1, SensorType.Clock, this, settings);
226 if (HasTimeStampCounter)
227 ActivateSensor(coreClocks[i]);
230 if (microarchitecture == Microarchitecture.SandyBridge) {
232 powerSensors = new Sensor[energyStatusMSRs.Length];
233 lastEnergyTime = new DateTime[energyStatusMSRs.Length];
234 lastEnergyConsumed = new uint[energyStatusMSRs.Length];
237 if (Ring0.Rdmsr(MSR_RAPL_POWER_UNIT, out eax, out edx))
238 energyUnitMultiplier = 1.0f / (1 << (int)((eax >> 8) & 0x1FF));
240 if (energyUnitMultiplier != 0) {
241 for (int i = 0; i < energyStatusMSRs.Length; i++) {
242 if (!Ring0.Rdmsr(energyStatusMSRs[i], out eax, out edx))
245 lastEnergyTime[i] = DateTime.UtcNow;
246 lastEnergyConsumed[i] = eax;
247 powerSensors[i] = new Sensor(powerSensorLabels[i], i,
248 SensorType.Power, this, settings);
249 ActivateSensor(powerSensors[i]);
257 protected override uint[] GetMSRs() {
261 IA32_THERM_STATUS_MSR,
262 IA32_TEMPERATURE_TARGET,
263 IA32_PACKAGE_THERM_STATUS,
265 MSR_PKG_ENERY_STATUS,
266 MSR_DRAM_ENERGY_STATUS,
267 MSR_PP0_ENERY_STATUS,
272 public override string GetReport() {
273 StringBuilder r = new StringBuilder();
274 r.Append(base.GetReport());
276 r.Append("Microarchitecture: ");
277 r.AppendLine(microarchitecture.ToString());
278 r.Append("Time Stamp Counter Multiplier: ");
279 r.AppendLine(timeStampCounterMultiplier.ToString(
280 CultureInfo.InvariantCulture));
286 public override void Update() {
289 for (int i = 0; i < coreTemperatures.Length; i++) {
292 IA32_THERM_STATUS_MSR, out eax, out edx,
293 1UL << cpuid[i][0].Thread)) {
294 // if reading is valid
295 if ((eax & 0x80000000) != 0) {
296 // get the dist from tjMax from bits 22:16
297 float deltaT = ((eax & 0x007F0000) >> 16);
298 float tjMax = coreTemperatures[i].Parameters[0].Value;
299 float tSlope = coreTemperatures[i].Parameters[1].Value;
300 coreTemperatures[i].Value = tjMax - tSlope * deltaT;
302 coreTemperatures[i].Value = null;
307 if (packageTemperature != null) {
310 IA32_PACKAGE_THERM_STATUS, out eax, out edx,
311 1UL << cpuid[0][0].Thread)) {
312 // get the dist from tjMax from bits 22:16
313 float deltaT = ((eax & 0x007F0000) >> 16);
314 float tjMax = packageTemperature.Parameters[0].Value;
315 float tSlope = packageTemperature.Parameters[1].Value;
316 packageTemperature.Value = tjMax - tSlope * deltaT;
318 packageTemperature.Value = null;
322 if (HasTimeStampCounter) {
323 double newBusClock = 0;
325 for (int i = 0; i < coreClocks.Length; i++) {
326 System.Threading.Thread.Sleep(1);
327 if (Ring0.RdmsrTx(IA32_PERF_STATUS, out eax, out edx,
328 1UL << cpuid[i][0].Thread)) {
330 TimeStampCounterFrequency / timeStampCounterMultiplier;
331 switch (microarchitecture) {
332 case Microarchitecture.Nehalem: {
333 uint multiplier = eax & 0xff;
334 coreClocks[i].Value = (float)(multiplier * newBusClock);
336 case Microarchitecture.SandyBridge: {
337 uint multiplier = (eax >> 8) & 0xff;
338 coreClocks[i].Value = (float)(multiplier * newBusClock);
342 ((eax >> 8) & 0x1f) + 0.5 * ((eax >> 14) & 1);
343 coreClocks[i].Value = (float)(multiplier * newBusClock);
347 // if IA32_PERF_STATUS is not available, assume TSC frequency
348 coreClocks[i].Value = (float)TimeStampCounterFrequency;
351 if (newBusClock > 0) {
352 this.busClock.Value = (float)newBusClock;
353 ActivateSensor(this.busClock);
357 if (powerSensors != null) {
358 foreach (Sensor sensor in powerSensors) {
363 if (!Ring0.Rdmsr(energyStatusMSRs[sensor.Index], out eax, out edx))
366 DateTime time = DateTime.UtcNow;
367 uint energyConsumed = eax;
369 (float)(time - lastEnergyTime[sensor.Index]).TotalSeconds;
370 if (deltaTime < 0.01)
373 sensor.Value = energyUnitMultiplier * unchecked(
374 energyConsumed - lastEnergyConsumed[sensor.Index]) / deltaTime;
375 lastEnergyTime[sensor.Index] = time;
376 lastEnergyConsumed[sensor.Index] = energyConsumed;