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