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