Added support for sensor parameters. Fixed Core and Thread count detection for Intel Core i7 CPUs with disabled HyperThreading.
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-2010
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.Collections.Generic;
41 using System.Diagnostics;
42 using System.Reflection;
43 using System.Runtime.InteropServices;
44 using System.Threading;
47 namespace OpenHardwareMonitor.Hardware.CPU {
48 public class IntelCPU : Hardware, IHardware {
55 private uint stepping;
57 private Sensor[] coreTemperatures;
59 private Sensor totalLoad;
60 private Sensor[] coreLoads;
61 private Sensor[] coreClocks;
62 private Sensor busClock;
63 private uint logicalProcessors;
64 private uint logicalProcessorsPerCore;
65 private uint coreCount;
66 private ulong affinityMask;
68 private CPULoad cpuLoad;
70 private ulong lastCount;
71 private long lastTime;
72 private uint maxNehalemMultiplier = 0;
74 private const uint IA32_THERM_STATUS_MSR = 0x019C;
75 private const uint IA32_TEMPERATURE_TARGET = 0x01A2;
76 private const uint IA32_PERF_STATUS = 0x0198;
77 private const uint MSR_PLATFORM_INFO = 0xCE;
79 private string CoreString(int i) {
83 return "CPU Core #" + (i + 1);
86 [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
87 private static extern bool GetProcessAffinityMask(IntPtr handle,
88 out IntPtr processMask, out IntPtr systemMask);
90 public IntelCPU(string name, uint family, uint model, uint stepping,
91 uint[,] cpuidData, uint[,] cpuidExtData) {
94 this.icon = Utilities.EmbeddedResources.GetImage("cpu.png");
98 this.stepping = stepping;
100 logicalProcessors = 0;
101 if (cpuidData.GetLength(0) > 0x0B) {
102 uint eax, ebx, ecx, edx;
103 WinRing0.CpuidEx(0x0B, 0, out eax, out ebx, out ecx, out edx);
104 logicalProcessorsPerCore = ebx & 0xFF;
105 if (logicalProcessorsPerCore > 0) {
106 WinRing0.CpuidEx(0x0B, 1, out eax, out ebx, out ecx, out edx);
107 logicalProcessors = ebx & 0xFF;
110 if (logicalProcessors <= 0 && cpuidData.GetLength(0) > 0x04) {
111 uint coresPerPackage = ((cpuidData[4, 0] >> 26) & 0x3F) + 1;
112 uint logicalPerPackage = (cpuidData[1, 1] >> 16) & 0xFF;
113 logicalProcessorsPerCore = logicalPerPackage / coresPerPackage;
114 logicalProcessors = logicalPerPackage;
116 if (logicalProcessors <= 0 && cpuidData.GetLength(0) > 0x01) {
117 uint logicalPerPackage = (cpuidData[1, 1] >> 16) & 0xFF;
118 logicalProcessorsPerCore = logicalPerPackage;
119 logicalProcessors = logicalPerPackage;
121 if (logicalProcessors <= 0) {
122 logicalProcessors = 1;
123 logicalProcessorsPerCore = 1;
126 IntPtr processMask, systemMask;
127 GetProcessAffinityMask(Process.GetCurrentProcess().Handle,
128 out processMask, out systemMask);
129 affinityMask = (ulong)systemMask;
131 // correct values in case HypeThreading is disabled
132 if (logicalProcessorsPerCore > 1) {
133 ulong affinity = affinityMask;
134 int availableLogicalProcessors = 0;
135 while (affinity != 0) {
136 if ((affinity & 0x1) > 0)
137 availableLogicalProcessors++;
140 while (logicalProcessorsPerCore > 1 &&
141 availableLogicalProcessors < logicalProcessors) {
142 logicalProcessors >>= 1;
143 logicalProcessorsPerCore >>= 1;
147 coreCount = logicalProcessors / logicalProcessorsPerCore;
153 case 0x0F: // Intel Core (65nm)
158 tjMax = 80 + 10; break;
160 tjMax = 90 + 10; break;
162 tjMax = 85 + 10; break;
164 tjMax = 80 + 10; break;
166 tjMax = 90 + 10; break;
168 tjMax = 85 + 10; break;
170 tjMax = 85 + 10; break;
172 case 0x17: // Intel Core (45nm)
174 case 0x1C: // Intel Atom
176 case 0x1A: // Intel Core i7 LGA1366 (45nm)
177 case 0x1E: // Intel Core i5, i7 LGA1156 (45nm)
178 case 0x25: // Intel Core i3, i5, i7 LGA1156 (32nm)
180 if (WinRing0.Rdmsr(IA32_TEMPERATURE_TARGET, out eax, out edx)) {
181 tjMax = (eax >> 16) & 0xFF;
185 if (WinRing0.Rdmsr(MSR_PLATFORM_INFO, out eax, out edx)) {
186 maxNehalemMultiplier = (eax >> 8) & 0xff;
193 default: tjMax = 100; break;
196 // check if processor supports a digital thermal sensor
197 if (cpuidData.GetLength(0) > 6 && (cpuidData[6, 0] & 1) != 0) {
198 coreTemperatures = new Sensor[coreCount];
199 for (int i = 0; i < coreTemperatures.Length; i++) {
200 coreTemperatures[i] = new Sensor(CoreString(i), i, tjMax,
201 SensorType.Temperature, this, new ParameterDescription[] {
202 new ParameterDescription(
203 "TjMax", "TjMax temperature of the core.\n" +
204 "Temperature = TjMax - TSlope * Value.", tjMax),
205 new ParameterDescription(
206 "TSlope", "Temperature slope of the digital thermal sensor.\n" +
207 "Temperature = TjMax - TSlope * Value.", 1)});
210 coreTemperatures = new Sensor[0];
214 totalLoad = new Sensor("CPU Total", 0, SensorType.Load, this);
217 coreLoads = new Sensor[coreCount];
218 for (int i = 0; i < coreLoads.Length; i++)
219 coreLoads[i] = new Sensor(CoreString(i), i + 1,
220 SensorType.Load, this);
221 cpuLoad = new CPULoad(coreCount, logicalProcessorsPerCore);
222 if (cpuLoad.IsAvailable) {
223 foreach (Sensor sensor in coreLoads)
224 ActivateSensor(sensor);
225 if (totalLoad != null)
226 ActivateSensor(totalLoad);
231 busClock = new Sensor("Bus Speed", 0, SensorType.Clock, this);
232 coreClocks = new Sensor[coreCount];
233 for (int i = 0; i < coreClocks.Length; i++) {
235 new Sensor(CoreString(i), i + 1, SensorType.Clock, this);
236 ActivateSensor(coreClocks[i]);
246 public string Identifier {
247 get { return "/intelcpu/0"; }
254 private void AppendMSRData(StringBuilder r, uint msr, int core) {
256 if (WinRing0.RdmsrTx(msr, out eax, out edx,
257 (UIntPtr)(1 << (int)(logicalProcessorsPerCore * core)))) {
259 r.Append((msr).ToString("X8"));
261 r.Append((edx).ToString("X8"));
263 r.Append((eax).ToString("X8"));
268 public string GetReport() {
269 StringBuilder r = new StringBuilder();
271 r.AppendLine("Intel CPU");
273 r.AppendFormat("Name: {0}{1}", name, Environment.NewLine);
274 r.AppendFormat("Number of Cores: {0}{1}", coreCount,
275 Environment.NewLine);
276 r.AppendFormat("Threads per Core: {0}{1}", logicalProcessorsPerCore,
277 Environment.NewLine);
278 r.AppendFormat("Affinity Mask: 0x{0}{1}", affinityMask.ToString("X"),
279 Environment.NewLine);
282 for (int i = 0; i < coreCount; i++) {
283 r.AppendLine("MSR Core #" + (i + 1));
285 r.AppendLine(" MSR EDX EAX");
286 AppendMSRData(r, MSR_PLATFORM_INFO, i);
287 AppendMSRData(r, IA32_PERF_STATUS, i);
288 AppendMSRData(r, IA32_THERM_STATUS_MSR, i);
289 AppendMSRData(r, IA32_TEMPERATURE_TARGET, i);
296 public void Update() {
298 for (int i = 0; i < coreTemperatures.Length; i++) {
300 if (WinRing0.RdmsrTx(
301 IA32_THERM_STATUS_MSR, out eax, out edx,
302 (UIntPtr)(1 << (int)(logicalProcessorsPerCore * i))))
304 // if reading is valid
305 if ((eax & 0x80000000) != 0) {
306 // get the dist from tjMax from bits 22:16
307 float deltaT = ((eax & 0x007F0000) >> 16);
308 float tjMax = coreTemperatures[i].Parameters[0].Value;
309 float tSlope = coreTemperatures[i].Parameters[1].Value;
310 coreTemperatures[i].Value = tjMax - tSlope * deltaT;
311 ActivateSensor(coreTemperatures[i]);
313 DeactivateSensor(coreTemperatures[i]);
318 if (cpuLoad.IsAvailable) {
320 for (int i = 0; i < coreLoads.Length; i++)
321 coreLoads[i].Value = cpuLoad.GetCoreLoad(i);
322 if (totalLoad != null)
323 totalLoad.Value = cpuLoad.GetTotalLoad();
327 bool valid = WinRing0.RdtscTx(out lsb, out msb, (UIntPtr)1);
328 long time = Stopwatch.GetTimestamp();
329 ulong count = ((ulong)msb << 32) | lsb;
330 double delta = ((double)(time - lastTime)) / Stopwatch.Frequency;
331 if (valid && delta > 0.5) {
332 double maxClock = (count - lastCount) / (1e6 * delta);
335 for (int i = 0; i < coreClocks.Length; i++) {
336 System.Threading.Thread.Sleep(1);
337 if (WinRing0.RdmsrTx(IA32_PERF_STATUS, out eax, out edx,
338 (UIntPtr)(1 << (int)(logicalProcessorsPerCore * i)))) {
339 if (maxNehalemMultiplier > 0) { // Core i3, i5, i7
340 uint nehalemMultiplier = eax & 0xff;
341 coreClocks[i].Value =
342 (float)(nehalemMultiplier * maxClock / maxNehalemMultiplier);
343 busClock = (float)(maxClock / maxNehalemMultiplier);
345 uint multiplier = (eax >> 8) & 0x1f;
346 uint maxMultiplier = (edx >> 8) & 0x1f;
347 // factor = multiplier * 2 to handle non integer multipliers
348 uint factor = (multiplier << 1) | ((eax >> 14) & 1);
349 uint maxFactor = (maxMultiplier << 1) | ((edx >> 14) & 1);
351 coreClocks[i].Value = (float)(factor * maxClock / maxFactor);
352 busClock = (float)(2 * maxClock / maxFactor);
355 } else { // Intel Pentium 4
356 // if IA32_PERF_STATUS is not available, assume maxClock
357 coreClocks[i].Value = (float)maxClock;
361 this.busClock.Value = (float)busClock;
362 ActivateSensor(this.busClock);