Hardware/CPU/IntelCPU.cs
author moel.mich
Sat, 06 Aug 2011 17:27:55 +0000
changeset 320 df3493f75225
parent 317 1ccf99e620a9
child 321 1da7448c8e10
permissions -rw-r--r--
Added Added a mainboard specific configuration for the Shuttle SH67Hx barebones. Added the SMBIOS system information to the report.
     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-2011
    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.Globalization;
    40 using System.Text;
    41 
    42 namespace OpenHardwareMonitor.Hardware.CPU {
    43   internal sealed class IntelCPU : GenericCPU {
    44 
    45     private enum Microarchitecture {
    46       Unknown,
    47       NetBurst,
    48       Core,
    49       Atom,
    50       Nehalem,
    51       SandyBridge
    52     }
    53 
    54     private readonly Sensor[] coreTemperatures;
    55     private readonly Sensor packageTemperature;
    56     private readonly Sensor[] coreClocks;
    57     private readonly Sensor busClock;
    58     private readonly Sensor packagePower;
    59     private readonly Sensor coresPower;
    60 
    61     private readonly Microarchitecture microarchitecture;
    62     private readonly double timeStampCounterMultiplier;
    63 
    64     private const uint IA32_THERM_STATUS_MSR = 0x019C;
    65     private const uint IA32_TEMPERATURE_TARGET = 0x01A2;
    66     private const uint IA32_PERF_STATUS = 0x0198;
    67     private const uint MSR_PLATFORM_INFO = 0xCE;
    68     private const uint IA32_PACKAGE_THERM_STATUS = 0x1B1;
    69     private const uint MSR_RAPL_POWER_UNIT = 0x606;
    70     private const uint MSR_PKG_ENERY_STATUS = 0x611;
    71     private const uint MSR_PP0_ENERY_STATUS = 0x639;
    72     private const uint MSR_PP1_ENERY_STATUS = 0x641;
    73 
    74     private float energyUnitMultiplier = 0;
    75     private DateTime lastPackageTime;
    76     private uint lastPackageEnergyConsumed;
    77     private DateTime lastCoresTime;
    78     private uint lastCoresEnergyConsumed;
    79 
    80 
    81 
    82     private float[] Floats(float f) {
    83       float[] result = new float[coreCount];
    84       for (int i = 0; i < coreCount; i++)
    85         result[i] = f;
    86       return result;
    87     }
    88 
    89     private float[] GetTjMaxFromMSR() {
    90       uint eax, edx;
    91       float[] result = new float[coreCount];
    92       for (int i = 0; i < coreCount; i++) {
    93         if (Ring0.RdmsrTx(IA32_TEMPERATURE_TARGET, out eax,
    94           out edx, 1UL << cpuid[i][0].Thread)) {
    95           result[i] = (eax >> 16) & 0xFF;
    96         } else {
    97           result[i] = 100;
    98         }
    99       }
   100       return result;
   101     }
   102 
   103     public IntelCPU(int processorIndex, CPUID[][] cpuid, ISettings settings)
   104       : base(processorIndex, cpuid, settings) 
   105     {
   106       // set tjMax
   107       float[] tjMax;
   108       switch (family) {
   109         case 0x06: {
   110             switch (model) {
   111               case 0x0F: // Intel Core 2 (65nm)
   112                 microarchitecture = Microarchitecture.Core;
   113                 switch (stepping) {
   114                   case 0x06: // B2
   115                     switch (coreCount) {
   116                       case 2:
   117                         tjMax = Floats(80 + 10); break;
   118                       case 4:
   119                         tjMax = Floats(90 + 10); break;
   120                       default:
   121                         tjMax = Floats(85 + 10); break;
   122                     }
   123                     tjMax = Floats(80 + 10); break;
   124                   case 0x0B: // G0
   125                     tjMax = Floats(90 + 10); break;
   126                   case 0x0D: // M0
   127                     tjMax = Floats(85 + 10); break;
   128                   default:
   129                     tjMax = Floats(85 + 10); break;
   130                 } break;
   131               case 0x17: // Intel Core 2 (45nm)
   132                 microarchitecture = Microarchitecture.Core;
   133                 tjMax = Floats(100); break;
   134               case 0x1C: // Intel Atom (45nm)
   135                 microarchitecture = Microarchitecture.Atom;
   136                 switch (stepping) {
   137                   case 0x02: // C0
   138                     tjMax = Floats(90); break;
   139                   case 0x0A: // A0, B0
   140                     tjMax = Floats(100); break;
   141                   default:
   142                     tjMax = Floats(90); break;
   143                 } break;
   144               case 0x1A: // Intel Core i7 LGA1366 (45nm)
   145               case 0x1E: // Intel Core i5, i7 LGA1156 (45nm)
   146               case 0x1F: // Intel Core i5, i7 
   147               case 0x25: // Intel Core i3, i5, i7 LGA1156 (32nm)
   148               case 0x2C: // Intel Core i7 LGA1366 (32nm) 6 Core
   149               case 0x2E: // Intel Xeon Processor 7500 series
   150                 microarchitecture = Microarchitecture.Nehalem;
   151                 tjMax = GetTjMaxFromMSR();
   152                 break;
   153               case 0x2A: // Intel Core i5, i7 2xxx LGA1155 (32nm)
   154               case 0x2D: // Next Generation Intel Xeon Processor
   155                 microarchitecture = Microarchitecture.SandyBridge;
   156                 tjMax = GetTjMaxFromMSR();
   157                 break;
   158               default:
   159                 microarchitecture = Microarchitecture.Unknown;
   160                 tjMax = Floats(100); 
   161                 break;
   162             }
   163           } break;
   164         case 0x0F: {
   165             switch (model) {
   166               case 0x00: // Pentium 4 (180nm)
   167               case 0x01: // Pentium 4 (130nm)
   168               case 0x02: // Pentium 4 (130nm)
   169               case 0x03: // Pentium 4, Celeron D (90nm)
   170               case 0x04: // Pentium 4, Pentium D, Celeron D (90nm)
   171               case 0x06: // Pentium 4, Pentium D, Celeron D (65nm)
   172                 microarchitecture = Microarchitecture.NetBurst;
   173                 tjMax = Floats(100); 
   174                 break;
   175               default:
   176                 microarchitecture = Microarchitecture.Unknown;
   177                 tjMax = Floats(100);
   178                 break;
   179             }
   180           } break;
   181         default:
   182           microarchitecture = Microarchitecture.Unknown;
   183           tjMax = Floats(100); 
   184           break;
   185       }
   186 
   187       // set timeStampCounterMultiplier
   188       switch (microarchitecture) {
   189         case Microarchitecture.NetBurst:
   190         case Microarchitecture.Atom:
   191         case Microarchitecture.Core: {
   192             uint eax, edx;
   193             if (Ring0.Rdmsr(IA32_PERF_STATUS, out eax, out edx)) {
   194               timeStampCounterMultiplier = 
   195                 ((edx >> 8) & 0x1f) + 0.5 * ((edx >> 14) & 1);
   196             }
   197           } break;
   198         case Microarchitecture.Nehalem: 
   199         case Microarchitecture.SandyBridge: {
   200             uint eax, edx;
   201             if (Ring0.Rdmsr(MSR_PLATFORM_INFO, out eax, out edx)) {
   202               timeStampCounterMultiplier = (eax >> 8) & 0xff;
   203             }
   204           } break;
   205         default: {
   206             timeStampCounterMultiplier = 1;
   207             uint eax, edx;
   208             if (Ring0.Rdmsr(IA32_PERF_STATUS, out eax, out edx)) {
   209               timeStampCounterMultiplier =
   210                 ((edx >> 8) & 0x1f) + 0.5 * ((edx >> 14) & 1);
   211             }
   212           } break;
   213       }
   214 
   215       // check if processor supports a digital thermal sensor at core level
   216       if (cpuid[0][0].Data.GetLength(0) > 6 &&
   217         (cpuid[0][0].Data[6, 0] & 1) != 0) 
   218       {
   219         coreTemperatures = new Sensor[coreCount];
   220         for (int i = 0; i < coreTemperatures.Length; i++) {
   221           coreTemperatures[i] = new Sensor(CoreString(i), i,
   222             SensorType.Temperature, this, new [] { 
   223               new ParameterDescription(
   224                 "TjMax [°C]", "TjMax temperature of the core sensor.\n" + 
   225                 "Temperature = TjMax - TSlope * Value.", tjMax[i]), 
   226               new ParameterDescription("TSlope [°C]", 
   227                 "Temperature slope of the digital thermal sensor.\n" + 
   228                 "Temperature = TjMax - TSlope * Value.", 1)}, settings);
   229           ActivateSensor(coreTemperatures[i]);
   230         }
   231       } else {
   232         coreTemperatures = new Sensor[0];
   233       }
   234 
   235       // check if processor supports a digital thermal sensor at package level
   236       if (cpuid[0][0].Data.GetLength(0) > 6 &&
   237         (cpuid[0][0].Data[6, 0] & 0x40) != 0) 
   238       {
   239           packageTemperature = new Sensor("CPU Package", 
   240             coreTemperatures.Length, SensorType.Temperature, this, new[] { 
   241               new ParameterDescription(
   242                 "TjMax [°C]", "TjMax temperature of the package sensor.\n" + 
   243                 "Temperature = TjMax - TSlope * Value.", tjMax[0]), 
   244               new ParameterDescription("TSlope [°C]", 
   245                 "Temperature slope of the digital thermal sensor.\n" + 
   246                 "Temperature = TjMax - TSlope * Value.", 1)}, settings);
   247         ActivateSensor(packageTemperature);
   248       } 
   249 
   250       busClock = new Sensor("Bus Speed", 0, SensorType.Clock, this, settings);
   251       coreClocks = new Sensor[coreCount];
   252       for (int i = 0; i < coreClocks.Length; i++) {
   253         coreClocks[i] =
   254           new Sensor(CoreString(i), i + 1, SensorType.Clock, this, settings);
   255         if (HasTimeStampCounter)
   256           ActivateSensor(coreClocks[i]);
   257       }
   258 
   259       if (microarchitecture == Microarchitecture.SandyBridge) {
   260         uint eax, edx;
   261         if (Ring0.Rdmsr(MSR_RAPL_POWER_UNIT, out eax, out edx))
   262           energyUnitMultiplier = 1.0f / (1 << (int)((eax >> 8) & 0x1FF));
   263 
   264 
   265         if (energyUnitMultiplier != 0 && 
   266           Ring0.Rdmsr(MSR_PKG_ENERY_STATUS, out eax, out edx)) 
   267         {
   268           lastPackageTime = DateTime.UtcNow;
   269           lastPackageEnergyConsumed = eax;
   270           packagePower = new Sensor("CPU Package", 0, SensorType.Power, this, 
   271             settings);          
   272           ActivateSensor(packagePower);
   273         }
   274 
   275         if (energyUnitMultiplier != 0 &&
   276           Ring0.Rdmsr(MSR_PP0_ENERY_STATUS, out eax, out edx)) 
   277         {
   278           lastCoresTime = DateTime.UtcNow;
   279           lastCoresEnergyConsumed = eax;
   280           coresPower = new Sensor("CPU Cores", 1, SensorType.Power, this,
   281             settings);
   282           ActivateSensor(coresPower);
   283         }
   284       }
   285 
   286       Update();
   287     }
   288 
   289     protected override uint[] GetMSRs() {
   290       return new [] {
   291         MSR_PLATFORM_INFO,
   292         IA32_PERF_STATUS ,
   293         IA32_THERM_STATUS_MSR,
   294         IA32_TEMPERATURE_TARGET,
   295         IA32_PACKAGE_THERM_STATUS,
   296         MSR_RAPL_POWER_UNIT,
   297         MSR_PKG_ENERY_STATUS,
   298         MSR_PP0_ENERY_STATUS,
   299         MSR_PP1_ENERY_STATUS
   300       };
   301     }
   302 
   303     public override string GetReport() {
   304       StringBuilder r = new StringBuilder();
   305       r.Append(base.GetReport());
   306 
   307       r.Append("Microarchitecture: ");
   308       r.AppendLine(microarchitecture.ToString());
   309       r.Append("Time Stamp Counter Multiplier: ");
   310       r.AppendLine(timeStampCounterMultiplier.ToString(
   311         CultureInfo.InvariantCulture));
   312       r.AppendLine();
   313 
   314       return r.ToString();
   315     }
   316 
   317     public override void Update() {
   318       base.Update();
   319 
   320       for (int i = 0; i < coreTemperatures.Length; i++) {
   321         uint eax, edx;
   322         if (Ring0.RdmsrTx(
   323           IA32_THERM_STATUS_MSR, out eax, out edx,
   324             1UL << cpuid[i][0].Thread)) {
   325           // if reading is valid
   326           if ((eax & 0x80000000) != 0) {
   327             // get the dist from tjMax from bits 22:16
   328             float deltaT = ((eax & 0x007F0000) >> 16);
   329             float tjMax = coreTemperatures[i].Parameters[0].Value;
   330             float tSlope = coreTemperatures[i].Parameters[1].Value;
   331             coreTemperatures[i].Value = tjMax - tSlope * deltaT;
   332           } else {
   333             coreTemperatures[i].Value = null;
   334           }
   335         }
   336       }
   337 
   338       if (packageTemperature != null) {
   339         uint eax, edx;
   340         if (Ring0.RdmsrTx(
   341           IA32_PACKAGE_THERM_STATUS, out eax, out edx,
   342             1UL << cpuid[0][0].Thread)) {
   343           // get the dist from tjMax from bits 22:16
   344           float deltaT = ((eax & 0x007F0000) >> 16);
   345           float tjMax = packageTemperature.Parameters[0].Value;
   346           float tSlope = packageTemperature.Parameters[1].Value;
   347           packageTemperature.Value = tjMax - tSlope * deltaT;
   348         } else {
   349           packageTemperature.Value = null;
   350         }
   351       }
   352 
   353       if (HasTimeStampCounter) {
   354         double newBusClock = 0;
   355         uint eax, edx;
   356         for (int i = 0; i < coreClocks.Length; i++) {
   357           System.Threading.Thread.Sleep(1);
   358           if (Ring0.RdmsrTx(IA32_PERF_STATUS, out eax, out edx,
   359             1UL << cpuid[i][0].Thread)) 
   360           {
   361             newBusClock = 
   362               TimeStampCounterFrequency / timeStampCounterMultiplier;
   363             switch (microarchitecture) {
   364               case Microarchitecture.Nehalem: {
   365                   uint multiplier = eax & 0xff;
   366                   coreClocks[i].Value = (float)(multiplier * newBusClock);
   367                 } break;
   368               case Microarchitecture.SandyBridge: {
   369                   uint multiplier = (eax >> 8) & 0xff;
   370                   coreClocks[i].Value = (float)(multiplier * newBusClock);
   371                 } break;
   372               default: {
   373                   double multiplier = 
   374                     ((eax >> 8) & 0x1f) + 0.5 * ((eax >> 14) & 1);
   375                   coreClocks[i].Value = (float)(multiplier * newBusClock);
   376                 } break;
   377             }         
   378           } else { 
   379             // if IA32_PERF_STATUS is not available, assume TSC frequency
   380             coreClocks[i].Value = (float)TimeStampCounterFrequency;
   381           }
   382         }
   383         if (newBusClock > 0) {
   384           this.busClock.Value = (float)newBusClock;
   385           ActivateSensor(this.busClock);
   386         }
   387       }
   388 
   389 
   390       if (packagePower != null) {
   391         uint eax, edx;
   392         if (Ring0.Rdmsr(MSR_PKG_ENERY_STATUS, out eax, out edx)) {
   393           DateTime time = DateTime.UtcNow;    
   394           uint energyConsumed = eax;
   395           float deltaTime = (float)(time - lastPackageTime).TotalSeconds;
   396           if (deltaTime > 0.01) {
   397             packagePower.Value = energyUnitMultiplier * 
   398               unchecked(energyConsumed - lastPackageEnergyConsumed) / deltaTime;
   399             lastPackageTime = time;
   400             lastPackageEnergyConsumed = energyConsumed;
   401           }
   402         }         
   403       }
   404 
   405       if (coresPower != null) {
   406         uint eax, edx;
   407         if (Ring0.Rdmsr(MSR_PP0_ENERY_STATUS, out eax, out edx)) {
   408           DateTime time = DateTime.UtcNow;
   409           uint energyConsumed = eax;
   410           float deltaTime = (float)(time - lastCoresTime).TotalSeconds;
   411           if (deltaTime > 0.01) {
   412             coresPower.Value = energyUnitMultiplier *
   413               unchecked(energyConsumed - lastCoresEnergyConsumed) / deltaTime;
   414             lastCoresTime = time;
   415             lastCoresEnergyConsumed = energyConsumed;
   416           }
   417         }
   418       }
   419     }
   420   }
   421 }