Hardware/CPU/IntelCPU.cs
author moel.mich
Tue, 02 Mar 2010 22:26:07 +0000
changeset 69 5f539c00e925
parent 63 1a7c13ac7348
child 79 9cdbe1d8d12a
permissions -rw-r--r--
Reading TjMax for each core on Intel Core i3/i5/i7 CPUs.
     1 /*
     2   
     3   Version: MPL 1.1/GPL 2.0/LGPL 2.1
     4 
     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
     8  
     9   http://www.mozilla.org/MPL/
    10 
    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.
    14 
    15   The Original Code is the Open Hardware Monitor code.
    16 
    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.
    21 
    22   Contributor(s):
    23 
    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.
    35  
    36 */
    37 
    38 using System;
    39 using System.Collections.Generic;
    40 using System.Drawing;
    41 using System.Diagnostics;
    42 using System.Reflection;
    43 using System.Runtime.InteropServices;
    44 using System.Threading;
    45 using System.Text;
    46 
    47 namespace OpenHardwareMonitor.Hardware.CPU {
    48   public class IntelCPU : Hardware, IHardware {
    49 
    50     private string name;
    51     private Image icon;
    52 
    53     private uint family;
    54     private uint model;
    55     private uint stepping;
    56 
    57     private Sensor[] coreTemperatures;
    58 
    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;
    67 
    68     private CPULoad cpuLoad;
    69 
    70     private ulong lastCount;    
    71     private long lastTime;
    72     private uint maxNehalemMultiplier = 0;
    73     
    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;
    78 
    79     private string CoreString(int i) {
    80       if (coreCount == 1)
    81         return "CPU Core";
    82       else
    83         return "CPU Core #" + (i + 1);
    84     }
    85 
    86     [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    87     private static extern bool GetProcessAffinityMask(IntPtr handle, 
    88       out IntPtr processMask, out IntPtr systemMask);
    89 
    90     private float[] Floats(float f) {
    91       float[] result = new float[coreCount];
    92       for (int i = 0; i < coreCount; i++)
    93         result[i] = f;
    94       return result;
    95     }
    96 
    97     public IntelCPU(string name, uint family, uint model, uint stepping, 
    98       uint[,] cpuidData, uint[,] cpuidExtData) {
    99       
   100       this.name = name;
   101       this.icon = Utilities.EmbeddedResources.GetImage("cpu.png");
   102 
   103       this.family = family;
   104       this.model = model;
   105       this.stepping = stepping;
   106 
   107       logicalProcessors = 0;
   108       if (cpuidData.GetLength(0) > 0x0B) {
   109         uint eax, ebx, ecx, edx;
   110         WinRing0.CpuidEx(0x0B, 0, out eax, out ebx, out ecx, out edx);
   111         logicalProcessorsPerCore = ebx & 0xFF;
   112         if (logicalProcessorsPerCore > 0) {
   113           WinRing0.CpuidEx(0x0B, 1, out eax, out ebx, out ecx, out edx);
   114           logicalProcessors = ebx & 0xFF;
   115         }   
   116       }
   117       if (logicalProcessors <= 0 && cpuidData.GetLength(0) > 0x04) {
   118         uint coresPerPackage = ((cpuidData[4, 0] >> 26) & 0x3F) + 1;
   119         uint logicalPerPackage = (cpuidData[1, 1] >> 16) & 0xFF;        
   120         logicalProcessorsPerCore = logicalPerPackage / coresPerPackage;
   121         logicalProcessors = logicalPerPackage;
   122       }
   123       if (logicalProcessors <= 0 && cpuidData.GetLength(0) > 0x01) {
   124         uint logicalPerPackage = (cpuidData[1, 1] >> 16) & 0xFF;
   125         logicalProcessorsPerCore = logicalPerPackage;
   126         logicalProcessors = logicalPerPackage;
   127       }
   128       if (logicalProcessors <= 0) {
   129         logicalProcessors = 1;
   130         logicalProcessorsPerCore = 1;
   131       }
   132 
   133       IntPtr processMask, systemMask;
   134       GetProcessAffinityMask(Process.GetCurrentProcess().Handle,
   135         out processMask, out systemMask);
   136       affinityMask = (ulong)systemMask;
   137 
   138       // correct values in case HypeThreading is disabled
   139       if (logicalProcessorsPerCore > 1) {
   140         ulong affinity = affinityMask;
   141         int availableLogicalProcessors = 0;
   142         while (affinity != 0) {
   143           if ((affinity & 0x1) > 0)
   144             availableLogicalProcessors++;
   145           affinity >>= 1;
   146         }
   147         while (logicalProcessorsPerCore > 1 &&
   148           availableLogicalProcessors < logicalProcessors) {
   149           logicalProcessors >>= 1;
   150           logicalProcessorsPerCore >>= 1;
   151         }
   152       }
   153 
   154       coreCount = logicalProcessors / logicalProcessorsPerCore;
   155 
   156       float[] tjMax;
   157       switch (family) {
   158         case 0x06: {
   159             switch (model) {
   160               case 0x0F: // Intel Core (65nm)
   161                 switch (stepping) {
   162                   case 0x06: // B2
   163                     switch (coreCount) {
   164                       case 2:
   165                         tjMax = Floats(80 + 10); break;
   166                       case 4:
   167                         tjMax = Floats(90 + 10); break;
   168                       default:
   169                         tjMax = Floats(85 + 10); break;
   170                     }
   171                     tjMax = Floats(80 + 10); break;
   172                   case 0x0B: // G0
   173                     tjMax = Floats(90 + 10); break;
   174                   case 0x0D: // M0
   175                     tjMax = Floats(85 + 10); break;
   176                   default:
   177                     tjMax = Floats(85 + 10); break;
   178                 } break;
   179               case 0x17: // Intel Core (45nm)
   180                 tjMax = Floats(100); break;
   181               case 0x1C: // Intel Atom 
   182                 tjMax = Floats(90); break;
   183               case 0x1A: // Intel Core i7 LGA1366 (45nm)
   184               case 0x1E: // Intel Core i5, i7 LGA1156 (45nm)
   185               case 0x25: // Intel Core i3, i5, i7 LGA1156 (32nm)
   186                 uint eax, edx;
   187                 tjMax = new float[coreCount];
   188                 for (int i = 0; i < coreCount; i++) {
   189                   if (WinRing0.RdmsrTx(IA32_TEMPERATURE_TARGET, out eax,
   190                     out edx, (UIntPtr)(
   191                     1 << (int)(logicalProcessorsPerCore * i)))) 
   192                   {
   193                     tjMax[i] = (eax >> 16) & 0xFF;
   194                   } else {
   195                     tjMax[i] = 100;
   196                   }
   197                 }
   198                 if (WinRing0.Rdmsr(MSR_PLATFORM_INFO, out eax, out edx)) {
   199                   maxNehalemMultiplier = (eax >> 8) & 0xff;
   200                 }
   201                 break;
   202               default:
   203                 tjMax = Floats(100); break;
   204             }
   205           } break;
   206         default: tjMax = Floats(100); break;
   207       }
   208 
   209       // check if processor supports a digital thermal sensor
   210       if (cpuidData.GetLength(0) > 6 && (cpuidData[6, 0] & 1) != 0) {
   211         coreTemperatures = new Sensor[coreCount];
   212         for (int i = 0; i < coreTemperatures.Length; i++) {
   213           coreTemperatures[i] = new Sensor(CoreString(i), i, tjMax[i],
   214             SensorType.Temperature, this, new ParameterDescription[] { 
   215               new ParameterDescription(
   216                 "TjMax", "TjMax temperature of the core.\n" + 
   217                 "Temperature = TjMax - TSlope * Value.", tjMax[i]), 
   218               new ParameterDescription(
   219                 "TSlope", "Temperature slope of the digital thermal sensor.\n" + 
   220                 "Temperature = TjMax - TSlope * Value.", 1)});
   221         }
   222       } else {
   223         coreTemperatures = new Sensor[0];
   224       }
   225 
   226       if (coreCount > 1)
   227         totalLoad = new Sensor("CPU Total", 0, SensorType.Load, this);
   228       else
   229         totalLoad = null;
   230       coreLoads = new Sensor[coreCount];
   231       for (int i = 0; i < coreLoads.Length; i++)
   232         coreLoads[i] = new Sensor(CoreString(i), i + 1,
   233           SensorType.Load, this);     
   234       cpuLoad = new CPULoad(coreCount, logicalProcessorsPerCore);
   235       if (cpuLoad.IsAvailable) {
   236         foreach (Sensor sensor in coreLoads)
   237           ActivateSensor(sensor);
   238         if (totalLoad != null)
   239           ActivateSensor(totalLoad);
   240       }
   241 
   242       lastCount = 0;
   243       lastTime = 0;
   244       busClock = new Sensor("Bus Speed", 0, SensorType.Clock, this);      
   245       coreClocks = new Sensor[coreCount];
   246       for (int i = 0; i < coreClocks.Length; i++) {
   247         coreClocks[i] =
   248           new Sensor(CoreString(i), i + 1, SensorType.Clock, this);
   249         ActivateSensor(coreClocks[i]);
   250       }
   251       
   252       Update();                   
   253     }
   254 
   255     public string Name {
   256       get { return name; }
   257     }
   258 
   259     public string Identifier {
   260       get { return "/intelcpu/0"; }
   261     }
   262 
   263     public Image Icon {
   264       get { return icon; }
   265     }
   266 
   267     private void AppendMSRData(StringBuilder r, uint msr, int core) {
   268       uint eax, edx;
   269       if (WinRing0.RdmsrTx(msr, out eax, out edx,
   270          (UIntPtr)(1 << (int)(logicalProcessorsPerCore * core)))) {
   271         r.Append(" ");
   272         r.Append((msr).ToString("X8"));
   273         r.Append("  ");
   274         r.Append((edx).ToString("X8"));
   275         r.Append("  ");
   276         r.Append((eax).ToString("X8"));
   277         r.AppendLine();
   278       }
   279     }
   280 
   281     public string GetReport() {
   282       StringBuilder r = new StringBuilder();
   283 
   284       r.AppendLine("Intel CPU");
   285       r.AppendLine();
   286       r.AppendFormat("Name: {0}{1}", name, Environment.NewLine);
   287       r.AppendFormat("Number of Cores: {0}{1}", coreCount, 
   288         Environment.NewLine);
   289       r.AppendFormat("Threads per Core: {0}{1}", logicalProcessorsPerCore,
   290         Environment.NewLine);
   291       r.AppendFormat("Affinity Mask: 0x{0}{1}", affinityMask.ToString("X"),
   292         Environment.NewLine);  
   293       r.AppendLine();
   294 
   295       for (int i = 0; i < coreCount; i++) {
   296         r.AppendLine("MSR Core #" + (i + 1));
   297         r.AppendLine();
   298         r.AppendLine(" MSR       EDX       EAX");
   299         AppendMSRData(r, MSR_PLATFORM_INFO, i);
   300         AppendMSRData(r, IA32_PERF_STATUS, i);
   301         AppendMSRData(r, IA32_THERM_STATUS_MSR, i);
   302         AppendMSRData(r, IA32_TEMPERATURE_TARGET, i);
   303         r.AppendLine();
   304       }
   305 
   306       return r.ToString();
   307     }
   308 
   309     public void Update() {
   310             
   311       for (int i = 0; i < coreTemperatures.Length; i++) {
   312         uint eax, edx;
   313         if (WinRing0.RdmsrTx(
   314           IA32_THERM_STATUS_MSR, out eax, out edx, 
   315             (UIntPtr)(1 << (int)(logicalProcessorsPerCore * i)))) 
   316         {
   317           // if reading is valid
   318           if ((eax & 0x80000000) != 0) {
   319             // get the dist from tjMax from bits 22:16
   320             float deltaT = ((eax & 0x007F0000) >> 16);
   321             float tjMax = coreTemperatures[i].Parameters[0].Value;
   322             float tSlope = coreTemperatures[i].Parameters[1].Value;
   323             coreTemperatures[i].Value = tjMax - tSlope * deltaT;
   324             ActivateSensor(coreTemperatures[i]);
   325           } else {
   326             DeactivateSensor(coreTemperatures[i]);
   327           }
   328         }        
   329       }
   330 
   331       if (cpuLoad.IsAvailable) {
   332         cpuLoad.Update();
   333         for (int i = 0; i < coreLoads.Length; i++)
   334           coreLoads[i].Value = cpuLoad.GetCoreLoad(i);
   335         if (totalLoad != null)
   336           totalLoad.Value = cpuLoad.GetTotalLoad();
   337       }
   338      
   339       uint lsb, msb;
   340       bool valid = WinRing0.RdtscTx(out lsb, out msb, (UIntPtr)1);
   341       long time = Stopwatch.GetTimestamp();
   342       ulong count = ((ulong)msb << 32) | lsb;
   343       double delta = ((double)(time - lastTime)) / Stopwatch.Frequency;
   344       if (valid && delta > 0.5) {
   345         double maxClock = (count - lastCount) / (1e6 * delta);
   346         double busClock = 0;
   347         uint eax, edx;
   348         for (int i = 0; i < coreClocks.Length; i++) {
   349           System.Threading.Thread.Sleep(1);
   350           if (WinRing0.RdmsrTx(IA32_PERF_STATUS, out eax, out edx,
   351             (UIntPtr)(1 << (int)(logicalProcessorsPerCore * i)))) {
   352             if (maxNehalemMultiplier > 0) { // Core i3, i5, i7
   353               uint nehalemMultiplier = eax & 0xff;
   354               coreClocks[i].Value =
   355                 (float)(nehalemMultiplier * maxClock / maxNehalemMultiplier);
   356               busClock = (float)(maxClock / maxNehalemMultiplier);
   357             } else { // Core 2
   358               uint multiplier = (eax >> 8) & 0x1f;
   359               uint maxMultiplier = (edx >> 8) & 0x1f;
   360               // factor = multiplier * 2 to handle non integer multipliers 
   361               uint factor = (multiplier << 1) | ((eax >> 14) & 1);
   362               uint maxFactor = (maxMultiplier << 1) | ((edx >> 14) & 1);
   363               if (maxFactor > 0) {
   364                 coreClocks[i].Value = (float)(factor * maxClock / maxFactor);
   365                 busClock = (float)(2 * maxClock / maxFactor);
   366               }
   367             }  
   368           } else { // Intel Pentium 4
   369             // if IA32_PERF_STATUS is not available, assume maxClock
   370             coreClocks[i].Value = (float)maxClock;
   371           }
   372         }
   373         if (busClock > 0) {
   374           this.busClock.Value = (float)busClock;
   375           ActivateSensor(this.busClock);
   376         }
   377       }
   378       lastCount = count;
   379       lastTime = time;
   380     }
   381   }  
   382 }