Hardware/CPU/IntelCPU.cs
author moel.mich
Sat, 27 Feb 2010 15:55:17 +0000
changeset 63 1a7c13ac7348
parent 52 8495c0ee29ac
child 69 5f539c00e925
permissions -rw-r--r--
Added support for sensor parameters. Fixed Core and Thread count detection for Intel Core i7 CPUs with disabled HyperThreading.
     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     public IntelCPU(string name, uint family, uint model, uint stepping, 
    91       uint[,] cpuidData, uint[,] cpuidExtData) {
    92       
    93       this.name = name;
    94       this.icon = Utilities.EmbeddedResources.GetImage("cpu.png");
    95 
    96       this.family = family;
    97       this.model = model;
    98       this.stepping = stepping;
    99 
   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;
   108         }   
   109       }
   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;
   115       }
   116       if (logicalProcessors <= 0 && cpuidData.GetLength(0) > 0x01) {
   117         uint logicalPerPackage = (cpuidData[1, 1] >> 16) & 0xFF;
   118         logicalProcessorsPerCore = logicalPerPackage;
   119         logicalProcessors = logicalPerPackage;
   120       }
   121       if (logicalProcessors <= 0) {
   122         logicalProcessors = 1;
   123         logicalProcessorsPerCore = 1;
   124       }
   125 
   126       IntPtr processMask, systemMask;
   127       GetProcessAffinityMask(Process.GetCurrentProcess().Handle,
   128         out processMask, out systemMask);
   129       affinityMask = (ulong)systemMask;
   130 
   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++;
   138           affinity >>= 1;
   139         }
   140         while (logicalProcessorsPerCore > 1 &&
   141           availableLogicalProcessors < logicalProcessors) {
   142           logicalProcessors >>= 1;
   143           logicalProcessorsPerCore >>= 1;
   144         }
   145       }
   146 
   147       coreCount = logicalProcessors / logicalProcessorsPerCore;
   148 
   149       float tjMax;
   150       switch (family) {
   151         case 0x06: {
   152             switch (model) {
   153               case 0x0F: // Intel Core (65nm)
   154                 switch (stepping) {
   155                   case 0x06: // B2
   156                     switch (coreCount) {
   157                       case 2:
   158                         tjMax = 80 + 10; break;
   159                       case 4:
   160                         tjMax = 90 + 10; break;
   161                       default:
   162                         tjMax = 85 + 10; break;
   163                     }
   164                     tjMax = 80 + 10; break;
   165                   case 0x0B: // G0
   166                     tjMax = 90 + 10; break;
   167                   case 0x0D: // M0
   168                     tjMax = 85 + 10; break;
   169                   default:
   170                     tjMax = 85 + 10; break;
   171                 } break;
   172               case 0x17: // Intel Core (45nm)
   173                 tjMax = 100; break;
   174               case 0x1C: // Intel Atom 
   175                 tjMax = 90; break;
   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)
   179                 uint eax, edx;
   180                 if (WinRing0.Rdmsr(IA32_TEMPERATURE_TARGET, out eax, out edx)) {
   181                   tjMax = (eax >> 16) & 0xFF;
   182                 } else {
   183                   tjMax = 100;
   184                 }
   185                 if (WinRing0.Rdmsr(MSR_PLATFORM_INFO, out eax, out edx)) {
   186                   maxNehalemMultiplier = (eax >> 8) & 0xff;
   187                 }
   188                 break;
   189               default:
   190                 tjMax = 100; break;
   191             }
   192           } break;
   193         default: tjMax = 100; break;
   194       }
   195 
   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)});
   208         }
   209       } else {
   210         coreTemperatures = new Sensor[0];
   211       }
   212 
   213       if (coreCount > 1)
   214         totalLoad = new Sensor("CPU Total", 0, SensorType.Load, this);
   215       else
   216         totalLoad = null;
   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);
   227       }
   228 
   229       lastCount = 0;
   230       lastTime = 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++) {
   234         coreClocks[i] =
   235           new Sensor(CoreString(i), i + 1, SensorType.Clock, this);
   236         ActivateSensor(coreClocks[i]);
   237       }
   238       
   239       Update();                   
   240     }
   241 
   242     public string Name {
   243       get { return name; }
   244     }
   245 
   246     public string Identifier {
   247       get { return "/intelcpu/0"; }
   248     }
   249 
   250     public Image Icon {
   251       get { return icon; }
   252     }
   253 
   254     private void AppendMSRData(StringBuilder r, uint msr, int core) {
   255       uint eax, edx;
   256       if (WinRing0.RdmsrTx(msr, out eax, out edx,
   257          (UIntPtr)(1 << (int)(logicalProcessorsPerCore * core)))) {
   258         r.Append(" ");
   259         r.Append((msr).ToString("X8"));
   260         r.Append("  ");
   261         r.Append((edx).ToString("X8"));
   262         r.Append("  ");
   263         r.Append((eax).ToString("X8"));
   264         r.AppendLine();
   265       }
   266     }
   267 
   268     public string GetReport() {
   269       StringBuilder r = new StringBuilder();
   270 
   271       r.AppendLine("Intel CPU");
   272       r.AppendLine();
   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);  
   280       r.AppendLine();
   281 
   282       for (int i = 0; i < coreCount; i++) {
   283         r.AppendLine("MSR Core #" + (i + 1));
   284         r.AppendLine();
   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);
   290         r.AppendLine();
   291       }
   292 
   293       return r.ToString();
   294     }
   295 
   296     public void Update() {
   297             
   298       for (int i = 0; i < coreTemperatures.Length; i++) {
   299         uint eax, edx;
   300         if (WinRing0.RdmsrTx(
   301           IA32_THERM_STATUS_MSR, out eax, out edx, 
   302             (UIntPtr)(1 << (int)(logicalProcessorsPerCore * i)))) 
   303         {
   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]);
   312           } else {
   313             DeactivateSensor(coreTemperatures[i]);
   314           }
   315         }        
   316       }
   317 
   318       if (cpuLoad.IsAvailable) {
   319         cpuLoad.Update();
   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();
   324       }
   325      
   326       uint lsb, msb;
   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);
   333         double busClock = 0;
   334         uint eax, edx;
   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);
   344             } else { // Core 2
   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);
   350               if (maxFactor > 0) {
   351                 coreClocks[i].Value = (float)(factor * maxClock / maxFactor);
   352                 busClock = (float)(2 * maxClock / maxFactor);
   353               }
   354             }  
   355           } else { // Intel Pentium 4
   356             // if IA32_PERF_STATUS is not available, assume maxClock
   357             coreClocks[i].Value = (float)maxClock;
   358           }
   359         }
   360         if (busClock > 0) {
   361           this.busClock.Value = (float)busClock;
   362           ActivateSensor(this.busClock);
   363         }
   364       }
   365       lastCount = count;
   366       lastTime = time;
   367     }
   368   }  
   369 }