Added an event handler to save the configuration when the user logs off without closing the application first (http://blogs.msdn.com/b/oldnewthing/archive/2008/04/21/8413175.aspx), because FormClosed is not called in that case.
     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.Globalization;
 
    43 using System.Reflection;
 
    44 using System.Runtime.InteropServices;
 
    45 using System.Threading;
 
    48 namespace OpenHardwareMonitor.Hardware.CPU {
 
    49   public class IntelCPU : Hardware, IHardware {
 
    51     private int processorIndex;
 
    52     private CPUID[][] cpuid;
 
    53     private int coreCount;
 
    60     private uint stepping;
 
    62     private Sensor[] coreTemperatures;
 
    64     private Sensor totalLoad;
 
    65     private Sensor[] coreLoads;
 
    66     private Sensor[] coreClocks;
 
    67     private Sensor busClock;    
 
    69     private bool invariantTSC;    
 
    70     private double estimatedMaxClock;
 
    72     private CPULoad cpuLoad;
 
    74     private ulong lastTimeStampCount;    
 
    75     private long lastTime;
 
    76     private uint maxNehalemMultiplier = 0;    
 
    78     private const uint IA32_THERM_STATUS_MSR = 0x019C;
 
    79     private const uint IA32_TEMPERATURE_TARGET = 0x01A2;
 
    80     private const uint IA32_PERF_STATUS = 0x0198;
 
    81     private const uint MSR_PLATFORM_INFO = 0xCE;
 
    83     private string CoreString(int i) {
 
    87         return "CPU Core #" + (i + 1);
 
    90     private float[] Floats(float f) {
 
    91       float[] result = new float[coreCount];
 
    92       for (int i = 0; i < coreCount; i++)
 
    97     public IntelCPU(int processorIndex, CPUID[][] cpuid) {
 
    99       this.processorIndex = processorIndex;
 
   101       this.coreCount = cpuid.Length;
 
   102       this.name = cpuid[0][0].Name;
 
   103       this.icon = Utilities.EmbeddedResources.GetImage("cpu.png");
 
   105       this.family = cpuid[0][0].Family;
 
   106       this.model = cpuid[0][0].Model;
 
   107       this.stepping = cpuid[0][0].Stepping;
 
   113               case 0x0F: // Intel Core (65nm)
 
   118                         tjMax = Floats(80 + 10); break;
 
   120                         tjMax = Floats(90 + 10); break;
 
   122                         tjMax = Floats(85 + 10); break;
 
   124                     tjMax = Floats(80 + 10); break;
 
   126                     tjMax = Floats(90 + 10); break;
 
   128                     tjMax = Floats(85 + 10); break;
 
   130                     tjMax = Floats(85 + 10); break;
 
   132               case 0x17: // Intel Core (45nm)
 
   133                 tjMax = Floats(100); break;
 
   134               case 0x1C: // Intel Atom (45nm)
 
   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 0x25: // Intel Core i3, i5, i7 LGA1156 (32nm)
 
   146               case 0x2C: // Intel Core i7 LGA1366 (32nm) 6 Core
 
   148                 tjMax = new float[coreCount];
 
   149                 for (int i = 0; i < coreCount; i++) {
 
   150                   if (WinRing0.RdmsrTx(IA32_TEMPERATURE_TARGET, out eax,
 
   151                     out edx, (UIntPtr)(1L << cpuid[i][0].Thread)))
 
   153                     tjMax[i] = (eax >> 16) & 0xFF;
 
   158                 if (WinRing0.Rdmsr(MSR_PLATFORM_INFO, out eax, out edx)) {
 
   159                   maxNehalemMultiplier = (eax >> 8) & 0xff;
 
   163                 tjMax = Floats(100); break;
 
   166         default: tjMax = Floats(100); break;
 
   169       // check if processor supports a digital thermal sensor
 
   170       if (cpuid[0][0].Data.GetLength(0) > 6 && 
 
   171         (cpuid[0][0].Data[6, 0] & 1) != 0) 
 
   173         coreTemperatures = new Sensor[coreCount];
 
   174         for (int i = 0; i < coreTemperatures.Length; i++) {
 
   175           coreTemperatures[i] = new Sensor(CoreString(i), i, tjMax[i],
 
   176             SensorType.Temperature, this, new ParameterDescription[] { 
 
   177               new ParameterDescription(
 
   178                 "TjMax [°C]", "TjMax temperature of the core.\n" + 
 
   179                 "Temperature = TjMax - TSlope * Value.", tjMax[i]), 
 
   180               new ParameterDescription("TSlope [°C]", 
 
   181                 "Temperature slope of the digital thermal sensor.\n" + 
 
   182                 "Temperature = TjMax - TSlope * Value.", 1)});
 
   185         coreTemperatures = new Sensor[0];
 
   189         totalLoad = new Sensor("CPU Total", 0, SensorType.Load, this);
 
   192       coreLoads = new Sensor[coreCount];
 
   193       for (int i = 0; i < coreLoads.Length; i++)
 
   194         coreLoads[i] = new Sensor(CoreString(i), i + 1,
 
   195           SensorType.Load, this);     
 
   196       cpuLoad = new CPULoad(cpuid);
 
   197       if (cpuLoad.IsAvailable) {
 
   198         foreach (Sensor sensor in coreLoads)
 
   199           ActivateSensor(sensor);
 
   200         if (totalLoad != null)
 
   201           ActivateSensor(totalLoad);
 
   204       // check if processor has TSC
 
   205       if (cpuid[0][0].Data.GetLength(0) > 1 
 
   206         && (cpuid[0][0].Data[1, 3] & 0x10) != 0)
 
   211       // check if processor supports invariant TSC 
 
   212       if (cpuid[0][0].ExtData.GetLength(0) > 7 
 
   213         && (cpuid[0][0].ExtData[7, 3] & 0x100) != 0)
 
   216         invariantTSC = false;
 
   218       // preload the function
 
   222       // estimate the max clock in MHz      
 
   223       List<double> estimatedMaxClocks = new List<double>(3);
 
   224       for (int i = 0; i < 3; i++)
 
   225         estimatedMaxClocks.Add(1e-6 * EstimateMaxClock(0.025));
 
   226       estimatedMaxClocks.Sort();
 
   227       estimatedMaxClock = estimatedMaxClocks[1];
 
   229       lastTimeStampCount = 0;
 
   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);
 
   237           ActivateSensor(coreClocks[i]);
 
   243     public override string Name {
 
   247     public override Identifier Identifier {
 
   248       get { return new Identifier("intelcpu", processorIndex.ToString()); }
 
   251     public override Image Icon {
 
   255     private void AppendMSRData(StringBuilder r, uint msr, int thread) {
 
   257       if (WinRing0.RdmsrTx(msr, out eax, out edx, (UIntPtr)(1L << thread))) {
 
   259         r.Append((msr).ToString("X8"));
 
   261         r.Append((edx).ToString("X8"));
 
   263         r.Append((eax).ToString("X8"));
 
   268     public override 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}", cpuid[0].Length,
 
   277         Environment.NewLine);     
 
   278       r.AppendLine("TSC: " + 
 
   279         (hasTSC ? (invariantTSC ? "Invariant" : "Not Invariant") : "None"));
 
   280       r.AppendLine(string.Format(CultureInfo.InvariantCulture, 
 
   281         "Timer Frequency: {0} MHz", Stopwatch.Frequency * 1e-6));
 
   282       r.AppendLine(string.Format(CultureInfo.InvariantCulture,
 
   283         "Max Clock: {0} MHz", Math.Round(estimatedMaxClock * 100) * 0.01));
 
   286       for (int i = 0; i < cpuid.Length; i++) {
 
   287         r.AppendLine("MSR Core #" + (i + 1));
 
   289         r.AppendLine(" MSR       EDX       EAX");
 
   290         AppendMSRData(r, MSR_PLATFORM_INFO, cpuid[i][0].Thread);
 
   291         AppendMSRData(r, IA32_PERF_STATUS, cpuid[i][0].Thread);
 
   292         AppendMSRData(r, IA32_THERM_STATUS_MSR, cpuid[i][0].Thread);
 
   293         AppendMSRData(r, IA32_TEMPERATURE_TARGET, cpuid[i][0].Thread);
 
   300     private double EstimateMaxClock(double timeWindow) {
 
   301       long ticks = (long)(timeWindow * Stopwatch.Frequency);
 
   302       uint lsbBegin, msbBegin, lsbEnd, msbEnd; 
 
   304       Thread.BeginThreadAffinity();
 
   305       long timeBegin = Stopwatch.GetTimestamp() + 
 
   306         (long)Math.Ceiling(0.001 * ticks);
 
   307       long timeEnd = timeBegin + ticks;      
 
   308       while (Stopwatch.GetTimestamp() < timeBegin) { }
 
   309       WinRing0.Rdtsc(out lsbBegin, out msbBegin);
 
   310       while (Stopwatch.GetTimestamp() < timeEnd) { }
 
   311       WinRing0.Rdtsc(out lsbEnd, out msbEnd);
 
   312       Thread.EndThreadAffinity();
 
   314       ulong countBegin = ((ulong)msbBegin << 32) | lsbBegin;
 
   315       ulong countEnd = ((ulong)msbEnd << 32) | lsbEnd;
 
   317       return (((double)(countEnd - countBegin)) * Stopwatch.Frequency) / 
 
   318         (timeEnd - timeBegin);
 
   321     public override void Update() {      
 
   322       for (int i = 0; i < coreTemperatures.Length; i++) {
 
   324         if (WinRing0.RdmsrTx(
 
   325           IA32_THERM_STATUS_MSR, out eax, out edx, 
 
   326             (UIntPtr)(1L << cpuid[i][0].Thread))) {
 
   327           // if reading is valid
 
   328           if ((eax & 0x80000000) != 0) {
 
   329             // get the dist from tjMax from bits 22:16
 
   330             float deltaT = ((eax & 0x007F0000) >> 16);
 
   331             float tjMax = coreTemperatures[i].Parameters[0].Value;
 
   332             float tSlope = coreTemperatures[i].Parameters[1].Value;
 
   333             coreTemperatures[i].Value = tjMax - tSlope * deltaT;
 
   334             ActivateSensor(coreTemperatures[i]);
 
   336             DeactivateSensor(coreTemperatures[i]);
 
   341       if (cpuLoad.IsAvailable) {
 
   343         for (int i = 0; i < coreLoads.Length; i++)
 
   344           coreLoads[i].Value = cpuLoad.GetCoreLoad(i);
 
   345         if (totalLoad != null)
 
   346           totalLoad.Value = cpuLoad.GetTotalLoad();
 
   351         WinRing0.RdtscTx(out lsb, out msb, (UIntPtr)1);
 
   352         long time = Stopwatch.GetTimestamp();
 
   353         ulong timeStampCount = ((ulong)msb << 32) | lsb;
 
   354         double delta = ((double)(time - lastTime)) / Stopwatch.Frequency;
 
   358             maxClock = (timeStampCount - lastTimeStampCount) / (1e6 * delta);
 
   360             maxClock = estimatedMaxClock;
 
   364           for (int i = 0; i < coreClocks.Length; i++) {
 
   365             System.Threading.Thread.Sleep(1);
 
   366             if (WinRing0.RdmsrTx(IA32_PERF_STATUS, out eax, out edx,
 
   367               (UIntPtr)(1L << cpuid[i][0].Thread))) {
 
   368               if (maxNehalemMultiplier > 0) { // Core i3, i5, i7
 
   369                 uint nehalemMultiplier = eax & 0xff;
 
   370                 coreClocks[i].Value =
 
   371                   (float)(nehalemMultiplier * maxClock / maxNehalemMultiplier);
 
   372                 busClock = (float)(maxClock / maxNehalemMultiplier);
 
   374                 uint multiplier = (eax >> 8) & 0x1f;
 
   375                 uint maxMultiplier = (edx >> 8) & 0x1f;
 
   376                 // factor = multiplier * 2 to handle non integer multipliers 
 
   377                 uint factor = (multiplier << 1) | ((eax >> 14) & 1);
 
   378                 uint maxFactor = (maxMultiplier << 1) | ((edx >> 14) & 1);
 
   380                   coreClocks[i].Value = (float)(factor * maxClock / maxFactor);
 
   381                   busClock = (float)(2 * maxClock / maxFactor);
 
   384             } else { // Intel Pentium 4
 
   385               // if IA32_PERF_STATUS is not available, assume maxClock
 
   386               coreClocks[i].Value = (float)maxClock;
 
   390             this.busClock.Value = (float)busClock;
 
   391             ActivateSensor(this.busClock);
 
   394         lastTimeStampCount = timeStampCount;