Hardware/CPU/IntelCPU.cs
author Stephane Lenclud
Sat, 30 Jan 2016 23:01:51 +0100
branchMiniDisplay
changeset 454 f84878f52cd9
parent 425 520bca5f2a7d
permissions -rw-r--r--
Disabling Nuvoton NCT6791D because of fan full speed bug on Asus Z97 WS.
     1 /*
     2  
     3   This Source Code Form is subject to the terms of the Mozilla Public
     4   License, v. 2.0. If a copy of the MPL was not distributed with this
     5   file, You can obtain one at http://mozilla.org/MPL/2.0/.
     6  
     7   Copyright (C) 2009-2014 Michael Möller <mmoeller@openhardwaremonitor.org>
     8 	
     9 */
    10 
    11 using System;
    12 using System.Globalization;
    13 using System.Text;
    14 
    15 namespace OpenHardwareMonitor.Hardware.CPU {
    16   internal sealed class IntelCPU : GenericCPU {
    17 
    18     private enum Microarchitecture {
    19       Unknown,
    20       NetBurst,
    21       Core,
    22       Atom,
    23       Nehalem,
    24       SandyBridge,
    25       IvyBridge,
    26       Haswell,
    27       Broadwell,
    28       Silvermont
    29     }
    30 
    31     private readonly Sensor[] coreTemperatures;
    32     private readonly Sensor packageTemperature;
    33     private readonly Sensor[] coreClocks;
    34     private readonly Sensor busClock;
    35     private readonly Sensor[] powerSensors;
    36 
    37     private readonly Microarchitecture microarchitecture;
    38     private readonly double timeStampCounterMultiplier;
    39 
    40     private const uint IA32_THERM_STATUS_MSR = 0x019C;
    41     private const uint IA32_TEMPERATURE_TARGET = 0x01A2;
    42     private const uint IA32_PERF_STATUS = 0x0198;
    43     private const uint MSR_PLATFORM_INFO = 0xCE;
    44     private const uint IA32_PACKAGE_THERM_STATUS = 0x1B1;
    45     private const uint MSR_RAPL_POWER_UNIT = 0x606;
    46     private const uint MSR_PKG_ENERY_STATUS = 0x611;
    47     private const uint MSR_DRAM_ENERGY_STATUS = 0x619;
    48     private const uint MSR_PP0_ENERY_STATUS = 0x639;
    49     private const uint MSR_PP1_ENERY_STATUS = 0x641;
    50 
    51     private readonly uint[] energyStatusMSRs = { MSR_PKG_ENERY_STATUS, 
    52       MSR_PP0_ENERY_STATUS, MSR_PP1_ENERY_STATUS, MSR_DRAM_ENERGY_STATUS };
    53     private readonly string[] powerSensorLabels = 
    54       { "CPU Package", "CPU Cores", "CPU Graphics", "CPU DRAM" };
    55     private float energyUnitMultiplier = 0;
    56     private DateTime[] lastEnergyTime;
    57     private uint[] lastEnergyConsumed;
    58 
    59 
    60     private float[] Floats(float f) {
    61       float[] result = new float[coreCount];
    62       for (int i = 0; i < coreCount; i++)
    63         result[i] = f;
    64       return result;
    65     }
    66 
    67     private float[] GetTjMaxFromMSR() {
    68       uint eax, edx;
    69       float[] result = new float[coreCount];
    70       for (int i = 0; i < coreCount; i++) {
    71         if (Ring0.RdmsrTx(IA32_TEMPERATURE_TARGET, out eax,
    72           out edx, 1UL << cpuid[i][0].Thread)) {
    73           result[i] = (eax >> 16) & 0xFF;
    74         } else {
    75           result[i] = 100;
    76         }
    77       }
    78       return result;
    79     }
    80 
    81     public IntelCPU(int processorIndex, CPUID[][] cpuid, ISettings settings)
    82       : base(processorIndex, cpuid, settings) {
    83       // set tjMax
    84       float[] tjMax;
    85       switch (family) {
    86         case 0x06: {
    87             switch (model) {
    88               case 0x0F: // Intel Core 2 (65nm)
    89                 microarchitecture = Microarchitecture.Core;
    90                 switch (stepping) {
    91                   case 0x06: // B2
    92                     switch (coreCount) {
    93                       case 2:
    94                         tjMax = Floats(80 + 10); break;
    95                       case 4:
    96                         tjMax = Floats(90 + 10); break;
    97                       default:
    98                         tjMax = Floats(85 + 10); break;
    99                     }
   100                     tjMax = Floats(80 + 10); break;
   101                   case 0x0B: // G0
   102                     tjMax = Floats(90 + 10); break;
   103                   case 0x0D: // M0
   104                     tjMax = Floats(85 + 10); break;
   105                   default:
   106                     tjMax = Floats(85 + 10); break;
   107                 } break;
   108               case 0x17: // Intel Core 2 (45nm)
   109                 microarchitecture = Microarchitecture.Core;
   110                 tjMax = Floats(100); break;
   111               case 0x1C: // Intel Atom (45nm)
   112                 microarchitecture = Microarchitecture.Atom;
   113                 switch (stepping) {
   114                   case 0x02: // C0
   115                     tjMax = Floats(90); break;
   116                   case 0x0A: // A0, B0
   117                     tjMax = Floats(100); break;
   118                   default:
   119                     tjMax = Floats(90); break;
   120                 } break;
   121               case 0x1A: // Intel Core i7 LGA1366 (45nm)
   122               case 0x1E: // Intel Core i5, i7 LGA1156 (45nm)
   123               case 0x1F: // Intel Core i5, i7 
   124               case 0x25: // Intel Core i3, i5, i7 LGA1156 (32nm)
   125               case 0x2C: // Intel Core i7 LGA1366 (32nm) 6 Core
   126               case 0x2E: // Intel Xeon Processor 7500 series (45nm)
   127               case 0x2F: // Intel Xeon Processor (32nm)
   128                 microarchitecture = Microarchitecture.Nehalem;
   129                 tjMax = GetTjMaxFromMSR();
   130                 break;
   131               case 0x2A: // Intel Core i5, i7 2xxx LGA1155 (32nm)
   132               case 0x2D: // Next Generation Intel Xeon, i7 3xxx LGA2011 (32nm)
   133                 microarchitecture = Microarchitecture.SandyBridge;
   134                 tjMax = GetTjMaxFromMSR();
   135                 break;
   136               case 0x3A: // Intel Core i5, i7 3xxx LGA1155 (22nm)
   137               case 0x3E: // Intel Core i7 4xxx LGA2011 (22nm)
   138                 microarchitecture = Microarchitecture.IvyBridge;
   139                 tjMax = GetTjMaxFromMSR();
   140                 break;
   141               case 0x3C: // Intel Core i5, i7 4xxx LGA1150 (22nm)              
   142               case 0x3F: // Intel Xeon E5-2600/1600 v3, Core i7-59xx
   143                          // LGA2011-v3, Haswell-E (22nm)
   144               case 0x45: // Intel Core i5, i7 4xxxU (22nm)
   145               case 0x46: 
   146                 microarchitecture = Microarchitecture.Haswell;
   147                 tjMax = GetTjMaxFromMSR();
   148                 break;
   149               case 0x3D: // Intel Core M-5xxx (14nm)
   150                 microarchitecture = Microarchitecture.Broadwell;
   151                 tjMax = GetTjMaxFromMSR();
   152                 break;
   153               case 0x36: // Intel Atom S1xxx, D2xxx, N2xxx (32nm)
   154                 microarchitecture = Microarchitecture.Atom;
   155                 tjMax = GetTjMaxFromMSR();
   156                 break;
   157               case 0x37: // Intel Atom E3xxx, Z3xxx (22nm)
   158               case 0x4A:
   159               case 0x4D: // Intel Atom C2xxx (22nm)
   160               case 0x5A:
   161               case 0x5D:
   162                 microarchitecture = Microarchitecture.Silvermont;
   163                 tjMax = GetTjMaxFromMSR();
   164                 break;
   165               default:
   166                 microarchitecture = Microarchitecture.Unknown;
   167                 tjMax = Floats(100);
   168                 break;
   169             }
   170           } break;
   171         case 0x0F: {
   172             switch (model) {
   173               case 0x00: // Pentium 4 (180nm)
   174               case 0x01: // Pentium 4 (130nm)
   175               case 0x02: // Pentium 4 (130nm)
   176               case 0x03: // Pentium 4, Celeron D (90nm)
   177               case 0x04: // Pentium 4, Pentium D, Celeron D (90nm)
   178               case 0x06: // Pentium 4, Pentium D, Celeron D (65nm)
   179                 microarchitecture = Microarchitecture.NetBurst;
   180                 tjMax = Floats(100);
   181                 break;
   182               default:
   183                 microarchitecture = Microarchitecture.Unknown;
   184                 tjMax = Floats(100);
   185                 break;
   186             }
   187           } break;
   188         default:
   189           microarchitecture = Microarchitecture.Unknown;
   190           tjMax = Floats(100);
   191           break;
   192       }
   193 
   194       // set timeStampCounterMultiplier
   195       switch (microarchitecture) {
   196         case Microarchitecture.NetBurst:
   197         case Microarchitecture.Atom:
   198         case Microarchitecture.Core: {
   199             uint eax, edx;
   200             if (Ring0.Rdmsr(IA32_PERF_STATUS, out eax, out edx)) {
   201               timeStampCounterMultiplier =
   202                 ((edx >> 8) & 0x1f) + 0.5 * ((edx >> 14) & 1);
   203             }
   204           } break;
   205         case Microarchitecture.Nehalem:
   206         case Microarchitecture.SandyBridge:
   207         case Microarchitecture.IvyBridge:
   208         case Microarchitecture.Haswell: 
   209         case Microarchitecture.Broadwell:
   210         case Microarchitecture.Silvermont: {
   211             uint eax, edx;
   212             if (Ring0.Rdmsr(MSR_PLATFORM_INFO, out eax, out edx)) {
   213               timeStampCounterMultiplier = (eax >> 8) & 0xff;
   214             }
   215           } break;
   216         default: 
   217           timeStampCounterMultiplier = 0;
   218           break;
   219       }
   220 
   221       // check if processor supports a digital thermal sensor at core level
   222       if (cpuid[0][0].Data.GetLength(0) > 6 &&
   223         (cpuid[0][0].Data[6, 0] & 1) != 0 && 
   224         microarchitecture != Microarchitecture.Unknown) 
   225       {
   226         coreTemperatures = new Sensor[coreCount];
   227         for (int i = 0; i < coreTemperatures.Length; i++) {
   228           coreTemperatures[i] = new Sensor(CoreString(i), i,
   229             SensorType.Temperature, this, new[] { 
   230               new ParameterDescription(
   231                 "TjMax [°C]", "TjMax temperature of the core sensor.\n" + 
   232                 "Temperature = TjMax - TSlope * Value.", tjMax[i]), 
   233               new ParameterDescription("TSlope [°C]", 
   234                 "Temperature slope of the digital thermal sensor.\n" + 
   235                 "Temperature = TjMax - TSlope * Value.", 1)}, settings);
   236           ActivateSensor(coreTemperatures[i]);
   237         }
   238       } else {
   239         coreTemperatures = new Sensor[0];
   240       }
   241 
   242       // check if processor supports a digital thermal sensor at package level
   243       if (cpuid[0][0].Data.GetLength(0) > 6 &&
   244         (cpuid[0][0].Data[6, 0] & 0x40) != 0 && 
   245         microarchitecture != Microarchitecture.Unknown) 
   246       {
   247         packageTemperature = new Sensor("CPU Package",
   248           coreTemperatures.Length, SensorType.Temperature, this, new[] { 
   249               new ParameterDescription(
   250                 "TjMax [°C]", "TjMax temperature of the package sensor.\n" + 
   251                 "Temperature = TjMax - TSlope * Value.", tjMax[0]), 
   252               new ParameterDescription("TSlope [°C]", 
   253                 "Temperature slope of the digital thermal sensor.\n" + 
   254                 "Temperature = TjMax - TSlope * Value.", 1)}, settings);
   255         ActivateSensor(packageTemperature);
   256       }
   257 
   258       busClock = new Sensor("Bus Speed", 0, SensorType.Clock, this, settings);
   259       coreClocks = new Sensor[coreCount];
   260       for (int i = 0; i < coreClocks.Length; i++) {
   261         coreClocks[i] =
   262           new Sensor(CoreString(i), i + 1, SensorType.Clock, this, settings);
   263         if (HasTimeStampCounter && microarchitecture != Microarchitecture.Unknown)
   264           ActivateSensor(coreClocks[i]);
   265       }
   266 
   267       if (microarchitecture == Microarchitecture.SandyBridge ||
   268           microarchitecture == Microarchitecture.IvyBridge ||
   269           microarchitecture == Microarchitecture.Haswell ||
   270           microarchitecture == Microarchitecture.Broadwell || 
   271           microarchitecture == Microarchitecture.Silvermont) 
   272       {
   273         powerSensors = new Sensor[energyStatusMSRs.Length];
   274         lastEnergyTime = new DateTime[energyStatusMSRs.Length];
   275         lastEnergyConsumed = new uint[energyStatusMSRs.Length];
   276 
   277         uint eax, edx;
   278         if (Ring0.Rdmsr(MSR_RAPL_POWER_UNIT, out eax, out edx))
   279           switch (microarchitecture) {
   280             case Microarchitecture.Silvermont:
   281               energyUnitMultiplier = 1.0e-6f * (1 << (int)((eax >> 8) & 0x1F));
   282               break;
   283             default:
   284               energyUnitMultiplier = 1.0f / (1 << (int)((eax >> 8) & 0x1F));
   285               break;
   286           }
   287         if (energyUnitMultiplier != 0) {
   288           for (int i = 0; i < energyStatusMSRs.Length; i++) {
   289             if (!Ring0.Rdmsr(energyStatusMSRs[i], out eax, out edx))
   290               continue;
   291 
   292             lastEnergyTime[i] = DateTime.UtcNow;
   293             lastEnergyConsumed[i] = eax;
   294             powerSensors[i] = new Sensor(powerSensorLabels[i], i,
   295               SensorType.Power, this, settings);
   296             ActivateSensor(powerSensors[i]);
   297           }
   298         }
   299       }
   300 
   301       Update();
   302     }
   303 
   304     protected override uint[] GetMSRs() {
   305       return new[] {
   306         MSR_PLATFORM_INFO,
   307         IA32_PERF_STATUS ,
   308         IA32_THERM_STATUS_MSR,
   309         IA32_TEMPERATURE_TARGET,
   310         IA32_PACKAGE_THERM_STATUS,
   311         MSR_RAPL_POWER_UNIT,
   312         MSR_PKG_ENERY_STATUS,
   313         MSR_DRAM_ENERGY_STATUS,
   314         MSR_PP0_ENERY_STATUS,
   315         MSR_PP1_ENERY_STATUS
   316       };
   317     }
   318 
   319     public override string GetReport() {
   320       StringBuilder r = new StringBuilder();
   321       r.Append(base.GetReport());
   322 
   323       r.Append("Microarchitecture: ");
   324       r.AppendLine(microarchitecture.ToString());
   325       r.Append("Time Stamp Counter Multiplier: ");
   326       r.AppendLine(timeStampCounterMultiplier.ToString(
   327         CultureInfo.InvariantCulture));
   328       r.AppendLine();
   329 
   330       return r.ToString();
   331     }
   332 
   333     public override void Update() {
   334       base.Update();
   335 
   336       for (int i = 0; i < coreTemperatures.Length; i++) {
   337         uint eax, edx;
   338         // if reading is valid
   339         if (Ring0.RdmsrTx(IA32_THERM_STATUS_MSR, out eax, out edx,
   340             1UL << cpuid[i][0].Thread) && (eax & 0x80000000) != 0) 
   341         {
   342           // get the dist from tjMax from bits 22:16
   343           float deltaT = ((eax & 0x007F0000) >> 16);
   344           float tjMax = coreTemperatures[i].Parameters[0].Value;
   345           float tSlope = coreTemperatures[i].Parameters[1].Value;
   346           coreTemperatures[i].Value = tjMax - tSlope * deltaT;
   347         } else {
   348           coreTemperatures[i].Value = null;
   349         }
   350       }
   351 
   352       if (packageTemperature != null) {
   353         uint eax, edx;
   354         // if reading is valid
   355         if (Ring0.RdmsrTx(IA32_PACKAGE_THERM_STATUS, out eax, out edx,
   356             1UL << cpuid[0][0].Thread) && (eax & 0x80000000) != 0) 
   357         {
   358           // get the dist from tjMax from bits 22:16
   359           float deltaT = ((eax & 0x007F0000) >> 16);
   360           float tjMax = packageTemperature.Parameters[0].Value;
   361           float tSlope = packageTemperature.Parameters[1].Value;
   362           packageTemperature.Value = tjMax - tSlope * deltaT;
   363         } else {
   364           packageTemperature.Value = null;
   365         }
   366       }
   367 
   368       if (HasTimeStampCounter && timeStampCounterMultiplier > 0) {
   369         double newBusClock = 0;
   370         uint eax, edx;
   371         for (int i = 0; i < coreClocks.Length; i++) {
   372           System.Threading.Thread.Sleep(1);
   373           if (Ring0.RdmsrTx(IA32_PERF_STATUS, out eax, out edx,
   374             1UL << cpuid[i][0].Thread)) {
   375             newBusClock =
   376               TimeStampCounterFrequency / timeStampCounterMultiplier;
   377             switch (microarchitecture) {
   378               case Microarchitecture.Nehalem: {
   379                   uint multiplier = eax & 0xff;
   380                   coreClocks[i].Value = (float)(multiplier * newBusClock);
   381                 } break;
   382               case Microarchitecture.SandyBridge:
   383               case Microarchitecture.IvyBridge:
   384               case Microarchitecture.Haswell: 
   385               case Microarchitecture.Broadwell:
   386               case Microarchitecture.Silvermont: {
   387                   uint multiplier = (eax >> 8) & 0xff;
   388                   coreClocks[i].Value = (float)(multiplier * newBusClock);
   389                 } break;
   390               default: {
   391                   double multiplier =
   392                     ((eax >> 8) & 0x1f) + 0.5 * ((eax >> 14) & 1);
   393                   coreClocks[i].Value = (float)(multiplier * newBusClock);
   394                 } break;
   395             }
   396           } else {
   397             // if IA32_PERF_STATUS is not available, assume TSC frequency
   398             coreClocks[i].Value = (float)TimeStampCounterFrequency;
   399           }
   400         }
   401         if (newBusClock > 0) {
   402           this.busClock.Value = (float)newBusClock;
   403           ActivateSensor(this.busClock);
   404         }
   405       }
   406 
   407       if (powerSensors != null) {
   408         foreach (Sensor sensor in powerSensors) {
   409           if (sensor == null)
   410             continue;
   411 
   412           uint eax, edx;
   413           if (!Ring0.Rdmsr(energyStatusMSRs[sensor.Index], out eax, out edx))
   414             continue;
   415 
   416           DateTime time = DateTime.UtcNow;
   417           uint energyConsumed = eax;
   418           float deltaTime =
   419             (float)(time - lastEnergyTime[sensor.Index]).TotalSeconds;
   420           if (deltaTime < 0.01)
   421             continue;
   422 
   423           sensor.Value = energyUnitMultiplier * unchecked(
   424             energyConsumed - lastEnergyConsumed[sensor.Index]) / deltaTime;
   425           lastEnergyTime[sensor.Index] = time;
   426           lastEnergyConsumed[sensor.Index] = energyConsumed;
   427         }
   428       }
   429     }
   430   }
   431 }