Fixed Issue 112.
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;
40 using System.Diagnostics;
41 using System.Globalization;
43 using System.Threading;
45 namespace OpenHardwareMonitor.Hardware.CPU {
46 internal sealed class IntelCPU : Hardware, IHardware {
48 private int processorIndex;
49 private CPUID[][] cpuid;
50 private int coreCount;
56 private uint stepping;
58 private Sensor[] coreTemperatures;
60 private Sensor totalLoad;
61 private Sensor[] coreLoads;
62 private Sensor[] coreClocks;
63 private Sensor busClock;
65 private bool invariantTSC;
66 private double estimatedMaxClock;
68 private CPULoad cpuLoad;
70 private ulong lastTimeStampCount;
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 private float[] Floats(float f) {
87 float[] result = new float[coreCount];
88 for (int i = 0; i < coreCount; i++)
93 public IntelCPU(int processorIndex, CPUID[][] cpuid, ISettings settings) {
95 this.processorIndex = processorIndex;
97 this.coreCount = cpuid.Length;
98 this.name = cpuid[0][0].Name;
100 this.family = cpuid[0][0].Family;
101 this.model = cpuid[0][0].Model;
102 this.stepping = cpuid[0][0].Stepping;
108 case 0x0F: // Intel Core (65nm)
113 tjMax = Floats(80 + 10); break;
115 tjMax = Floats(90 + 10); break;
117 tjMax = Floats(85 + 10); break;
119 tjMax = Floats(80 + 10); break;
121 tjMax = Floats(90 + 10); break;
123 tjMax = Floats(85 + 10); break;
125 tjMax = Floats(85 + 10); break;
127 case 0x17: // Intel Core (45nm)
128 tjMax = Floats(100); break;
129 case 0x1C: // Intel Atom (45nm)
132 tjMax = Floats(90); break;
134 tjMax = Floats(100); break;
136 tjMax = Floats(90); break;
138 case 0x1A: // Intel Core i7 LGA1366 (45nm)
139 case 0x1E: // Intel Core i5, i7 LGA1156 (45nm)
140 case 0x25: // Intel Core i3, i5, i7 LGA1156 (32nm)
141 case 0x2C: // Intel Core i7 LGA1366 (32nm) 6 Core
143 tjMax = new float[coreCount];
144 for (int i = 0; i < coreCount; i++) {
145 if (WinRing0.RdmsrTx(IA32_TEMPERATURE_TARGET, out eax,
146 out edx, (UIntPtr)(1L << cpuid[i][0].Thread)))
148 tjMax[i] = (eax >> 16) & 0xFF;
153 if (WinRing0.Rdmsr(MSR_PLATFORM_INFO, out eax, out edx)) {
154 maxNehalemMultiplier = (eax >> 8) & 0xff;
158 tjMax = Floats(100); break;
161 default: tjMax = Floats(100); break;
164 // check if processor supports a digital thermal sensor
165 if (cpuid[0][0].Data.GetLength(0) > 6 &&
166 (cpuid[0][0].Data[6, 0] & 1) != 0)
168 coreTemperatures = new Sensor[coreCount];
169 for (int i = 0; i < coreTemperatures.Length; i++) {
170 coreTemperatures[i] = new Sensor(CoreString(i), i,
171 SensorType.Temperature, this, new ParameterDescription[] {
172 new ParameterDescription(
173 "TjMax [°C]", "TjMax temperature of the core.\n" +
174 "Temperature = TjMax - TSlope * Value.", tjMax[i]),
175 new ParameterDescription("TSlope [°C]",
176 "Temperature slope of the digital thermal sensor.\n" +
177 "Temperature = TjMax - TSlope * Value.", 1)}, settings);
178 ActivateSensor(coreTemperatures[i]);
181 coreTemperatures = new Sensor[0];
185 totalLoad = new Sensor("CPU Total", 0, SensorType.Load, this, settings);
188 coreLoads = new Sensor[coreCount];
189 for (int i = 0; i < coreLoads.Length; i++)
190 coreLoads[i] = new Sensor(CoreString(i), i + 1,
191 SensorType.Load, this, settings);
192 cpuLoad = new CPULoad(cpuid);
193 if (cpuLoad.IsAvailable) {
194 foreach (Sensor sensor in coreLoads)
195 ActivateSensor(sensor);
196 if (totalLoad != null)
197 ActivateSensor(totalLoad);
200 // check if processor has TSC
201 if (cpuid[0][0].Data.GetLength(0) > 1
202 && (cpuid[0][0].Data[1, 3] & 0x10) != 0)
207 // check if processor supports invariant TSC
208 if (cpuid[0][0].ExtData.GetLength(0) > 7
209 && (cpuid[0][0].ExtData[7, 3] & 0x100) != 0)
212 invariantTSC = false;
214 // preload the function
218 // estimate the max clock in MHz
219 List<double> estimatedMaxClocks = new List<double>(3);
220 for (int i = 0; i < 3; i++)
221 estimatedMaxClocks.Add(1e-6 * EstimateMaxClock(0.025));
222 estimatedMaxClocks.Sort();
223 estimatedMaxClock = estimatedMaxClocks[1];
225 lastTimeStampCount = 0;
227 busClock = new Sensor("Bus Speed", 0, SensorType.Clock, this, settings);
228 coreClocks = new Sensor[coreCount];
229 for (int i = 0; i < coreClocks.Length; i++) {
231 new Sensor(CoreString(i), i + 1, SensorType.Clock, this, settings);
233 ActivateSensor(coreClocks[i]);
239 public override string Name {
243 public override Identifier Identifier {
245 return new Identifier("intelcpu",
246 processorIndex.ToString(CultureInfo.InvariantCulture));
250 public override HardwareType HardwareType {
251 get { return HardwareType.CPU; }
254 private static void AppendMSRData(StringBuilder r, uint msr, int thread) {
256 if (WinRing0.RdmsrTx(msr, out eax, out edx, (UIntPtr)(1L << thread))) {
258 r.Append((msr).ToString("X8", CultureInfo.InvariantCulture));
260 r.Append((edx).ToString("X8", CultureInfo.InvariantCulture));
262 r.Append((eax).ToString("X8", CultureInfo.InvariantCulture));
267 public override string GetReport() {
268 StringBuilder r = new StringBuilder();
270 r.AppendLine("Intel CPU");
272 r.AppendFormat("Name: {0}{1}", name, Environment.NewLine);
273 r.AppendFormat("Number of Cores: {0}{1}", coreCount,
274 Environment.NewLine);
275 r.AppendFormat("Threads per Core: {0}{1}", cpuid[0].Length,
276 Environment.NewLine);
277 r.AppendLine("TSC: " +
278 (hasTSC ? (invariantTSC ? "Invariant" : "Not Invariant") : "None"));
279 r.AppendLine(string.Format(CultureInfo.InvariantCulture,
280 "Timer Frequency: {0} MHz", Stopwatch.Frequency * 1e-6));
281 r.AppendLine(string.Format(CultureInfo.InvariantCulture,
282 "Max Clock: {0} MHz", Math.Round(estimatedMaxClock * 100) * 0.01));
285 for (int i = 0; i < cpuid.Length; i++) {
286 r.AppendLine("MSR Core #" + (i + 1));
288 r.AppendLine(" MSR EDX EAX");
289 AppendMSRData(r, MSR_PLATFORM_INFO, cpuid[i][0].Thread);
290 AppendMSRData(r, IA32_PERF_STATUS, cpuid[i][0].Thread);
291 AppendMSRData(r, IA32_THERM_STATUS_MSR, cpuid[i][0].Thread);
292 AppendMSRData(r, IA32_TEMPERATURE_TARGET, cpuid[i][0].Thread);
299 private static double EstimateMaxClock(double timeWindow) {
300 long ticks = (long)(timeWindow * Stopwatch.Frequency);
301 uint lsbBegin, msbBegin, lsbEnd, msbEnd;
303 Thread.BeginThreadAffinity();
304 long timeBegin = Stopwatch.GetTimestamp() +
305 (long)Math.Ceiling(0.001 * ticks);
306 long timeEnd = timeBegin + ticks;
307 while (Stopwatch.GetTimestamp() < timeBegin) { }
308 WinRing0.Rdtsc(out lsbBegin, out msbBegin);
309 while (Stopwatch.GetTimestamp() < timeEnd) { }
310 WinRing0.Rdtsc(out lsbEnd, out msbEnd);
311 Thread.EndThreadAffinity();
313 ulong countBegin = ((ulong)msbBegin << 32) | lsbBegin;
314 ulong countEnd = ((ulong)msbEnd << 32) | lsbEnd;
316 return (((double)(countEnd - countBegin)) * Stopwatch.Frequency) /
317 (timeEnd - timeBegin);
320 public override void Update() {
321 for (int i = 0; i < coreTemperatures.Length; i++) {
323 if (WinRing0.RdmsrTx(
324 IA32_THERM_STATUS_MSR, out eax, out edx,
325 (UIntPtr)(1L << cpuid[i][0].Thread))) {
326 // if reading is valid
327 if ((eax & 0x80000000) != 0) {
328 // get the dist from tjMax from bits 22:16
329 float deltaT = ((eax & 0x007F0000) >> 16);
330 float tjMax = coreTemperatures[i].Parameters[0].Value;
331 float tSlope = coreTemperatures[i].Parameters[1].Value;
332 coreTemperatures[i].Value = tjMax - tSlope * deltaT;
334 coreTemperatures[i].Value = null;
339 if (cpuLoad.IsAvailable) {
341 for (int i = 0; i < coreLoads.Length; i++)
342 coreLoads[i].Value = cpuLoad.GetCoreLoad(i);
343 if (totalLoad != null)
344 totalLoad.Value = cpuLoad.GetTotalLoad();
349 WinRing0.RdtscTx(out lsb, out msb, (UIntPtr)1);
350 long time = Stopwatch.GetTimestamp();
351 ulong timeStampCount = ((ulong)msb << 32) | lsb;
352 double delta = ((double)(time - lastTime)) / Stopwatch.Frequency;
356 maxClock = (timeStampCount - lastTimeStampCount) / (1e6 * delta);
358 maxClock = estimatedMaxClock;
360 double newBusClock = 0;
362 for (int i = 0; i < coreClocks.Length; i++) {
363 System.Threading.Thread.Sleep(1);
364 if (WinRing0.RdmsrTx(IA32_PERF_STATUS, out eax, out edx,
365 (UIntPtr)(1L << cpuid[i][0].Thread))) {
366 if (maxNehalemMultiplier > 0) { // Core i3, i5, i7
367 uint nehalemMultiplier = eax & 0xff;
368 coreClocks[i].Value =
369 (float)(nehalemMultiplier * maxClock / maxNehalemMultiplier);
370 newBusClock = (float)(maxClock / maxNehalemMultiplier);
372 uint multiplier = (eax >> 8) & 0x1f;
373 uint maxMultiplier = (edx >> 8) & 0x1f;
374 // factor = multiplier * 2 to handle non integer multipliers
375 uint factor = (multiplier << 1) | ((eax >> 14) & 1);
376 uint maxFactor = (maxMultiplier << 1) | ((edx >> 14) & 1);
378 coreClocks[i].Value = (float)(factor * maxClock / maxFactor);
379 newBusClock = (float)(2 * maxClock / maxFactor);
382 } else { // Intel Pentium 4
383 // if IA32_PERF_STATUS is not available, assume maxClock
384 coreClocks[i].Value = (float)maxClock;
387 if (newBusClock > 0) {
388 this.busClock.Value = (float)newBusClock;
389 ActivateSensor(this.busClock);
392 lastTimeStampCount = timeStampCount;