Hardware/CPU/IntelCPU.cs
author moel.mich
Thu, 01 Aug 2013 11:57:09 +0000
changeset 417 4865cf06a7fa
parent 396 c7e2a6aa4f96
child 418 3bba187d41c2
permissions -rw-r--r--
Added experimental support for Intel Ivy Bridge-E 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               case 0x3E: // Intel Core i7 4xxx LGA2011 (22nm)
   136                 microarchitecture = Microarchitecture.IvyBridge;
   137                 tjMax = GetTjMaxFromMSR();
   138                 break;
   139               case 0x3C: // Intel Core i5, i7 4xxx LGA1150 (22nm)
   140               case 0x45:
   141               case 0x46:
   142                 microarchitecture = Microarchitecture.Haswell;
   143                 tjMax = GetTjMaxFromMSR();
   144                 break;
   145               default:
   146                 microarchitecture = Microarchitecture.Unknown;
   147                 tjMax = Floats(100);
   148                 break;
   149             }
   150           } break;
   151         case 0x0F: {
   152             switch (model) {
   153               case 0x00: // Pentium 4 (180nm)
   154               case 0x01: // Pentium 4 (130nm)
   155               case 0x02: // Pentium 4 (130nm)
   156               case 0x03: // Pentium 4, Celeron D (90nm)
   157               case 0x04: // Pentium 4, Pentium D, Celeron D (90nm)
   158               case 0x06: // Pentium 4, Pentium D, Celeron D (65nm)
   159                 microarchitecture = Microarchitecture.NetBurst;
   160                 tjMax = Floats(100);
   161                 break;
   162               default:
   163                 microarchitecture = Microarchitecture.Unknown;
   164                 tjMax = Floats(100);
   165                 break;
   166             }
   167           } break;
   168         default:
   169           microarchitecture = Microarchitecture.Unknown;
   170           tjMax = Floats(100);
   171           break;
   172       }
   173 
   174       // set timeStampCounterMultiplier
   175       switch (microarchitecture) {
   176         case Microarchitecture.NetBurst:
   177         case Microarchitecture.Atom:
   178         case Microarchitecture.Core: {
   179             uint eax, edx;
   180             if (Ring0.Rdmsr(IA32_PERF_STATUS, out eax, out edx)) {
   181               timeStampCounterMultiplier =
   182                 ((edx >> 8) & 0x1f) + 0.5 * ((edx >> 14) & 1);
   183             }
   184           } break;
   185         case Microarchitecture.Nehalem:
   186         case Microarchitecture.SandyBridge:
   187         case Microarchitecture.IvyBridge:
   188         case Microarchitecture.Haswell: {
   189             uint eax, edx;
   190             if (Ring0.Rdmsr(MSR_PLATFORM_INFO, out eax, out edx)) {
   191               timeStampCounterMultiplier = (eax >> 8) & 0xff;
   192             }
   193           } break;
   194         default: 
   195           timeStampCounterMultiplier = 0;
   196           break;
   197       }
   198 
   199       // check if processor supports a digital thermal sensor at core level
   200       if (cpuid[0][0].Data.GetLength(0) > 6 &&
   201         (cpuid[0][0].Data[6, 0] & 1) != 0 && 
   202         microarchitecture != Microarchitecture.Unknown) 
   203       {
   204         coreTemperatures = new Sensor[coreCount];
   205         for (int i = 0; i < coreTemperatures.Length; i++) {
   206           coreTemperatures[i] = new Sensor(CoreString(i), i,
   207             SensorType.Temperature, this, new[] { 
   208               new ParameterDescription(
   209                 "TjMax [°C]", "TjMax temperature of the core sensor.\n" + 
   210                 "Temperature = TjMax - TSlope * Value.", tjMax[i]), 
   211               new ParameterDescription("TSlope [°C]", 
   212                 "Temperature slope of the digital thermal sensor.\n" + 
   213                 "Temperature = TjMax - TSlope * Value.", 1)}, settings);
   214           ActivateSensor(coreTemperatures[i]);
   215         }
   216       } else {
   217         coreTemperatures = new Sensor[0];
   218       }
   219 
   220       // check if processor supports a digital thermal sensor at package level
   221       if (cpuid[0][0].Data.GetLength(0) > 6 &&
   222         (cpuid[0][0].Data[6, 0] & 0x40) != 0 && 
   223         microarchitecture != Microarchitecture.Unknown) 
   224       {
   225         packageTemperature = new Sensor("CPU Package",
   226           coreTemperatures.Length, SensorType.Temperature, this, new[] { 
   227               new ParameterDescription(
   228                 "TjMax [°C]", "TjMax temperature of the package sensor.\n" + 
   229                 "Temperature = TjMax - TSlope * Value.", tjMax[0]), 
   230               new ParameterDescription("TSlope [°C]", 
   231                 "Temperature slope of the digital thermal sensor.\n" + 
   232                 "Temperature = TjMax - TSlope * Value.", 1)}, settings);
   233         ActivateSensor(packageTemperature);
   234       }
   235 
   236       busClock = new Sensor("Bus Speed", 0, SensorType.Clock, this, settings);
   237       coreClocks = new Sensor[coreCount];
   238       for (int i = 0; i < coreClocks.Length; i++) {
   239         coreClocks[i] =
   240           new Sensor(CoreString(i), i + 1, SensorType.Clock, this, settings);
   241         if (HasTimeStampCounter && microarchitecture != Microarchitecture.Unknown)
   242           ActivateSensor(coreClocks[i]);
   243       }
   244 
   245       if (microarchitecture == Microarchitecture.SandyBridge ||
   246           microarchitecture == Microarchitecture.IvyBridge ||
   247           microarchitecture == Microarchitecture.Haswell) 
   248       {
   249         powerSensors = new Sensor[energyStatusMSRs.Length];
   250         lastEnergyTime = new DateTime[energyStatusMSRs.Length];
   251         lastEnergyConsumed = new uint[energyStatusMSRs.Length];
   252 
   253         uint eax, edx;
   254         if (Ring0.Rdmsr(MSR_RAPL_POWER_UNIT, out eax, out edx))
   255           energyUnitMultiplier = 1.0f / (1 << (int)((eax >> 8) & 0x1FF));
   256 
   257         if (energyUnitMultiplier != 0) {
   258           for (int i = 0; i < energyStatusMSRs.Length; i++) {
   259             if (!Ring0.Rdmsr(energyStatusMSRs[i], out eax, out edx))
   260               continue;
   261 
   262             lastEnergyTime[i] = DateTime.UtcNow;
   263             lastEnergyConsumed[i] = eax;
   264             powerSensors[i] = new Sensor(powerSensorLabels[i], i,
   265               SensorType.Power, this, settings);
   266             ActivateSensor(powerSensors[i]);
   267           }
   268         }
   269       }
   270 
   271       Update();
   272     }
   273 
   274     protected override uint[] GetMSRs() {
   275       return new[] {
   276         MSR_PLATFORM_INFO,
   277         IA32_PERF_STATUS ,
   278         IA32_THERM_STATUS_MSR,
   279         IA32_TEMPERATURE_TARGET,
   280         IA32_PACKAGE_THERM_STATUS,
   281         MSR_RAPL_POWER_UNIT,
   282         MSR_PKG_ENERY_STATUS,
   283         MSR_DRAM_ENERGY_STATUS,
   284         MSR_PP0_ENERY_STATUS,
   285         MSR_PP1_ENERY_STATUS
   286       };
   287     }
   288 
   289     public override string GetReport() {
   290       StringBuilder r = new StringBuilder();
   291       r.Append(base.GetReport());
   292 
   293       r.Append("Microarchitecture: ");
   294       r.AppendLine(microarchitecture.ToString());
   295       r.Append("Time Stamp Counter Multiplier: ");
   296       r.AppendLine(timeStampCounterMultiplier.ToString(
   297         CultureInfo.InvariantCulture));
   298       r.AppendLine();
   299 
   300       return r.ToString();
   301     }
   302 
   303     public override void Update() {
   304       base.Update();
   305 
   306       for (int i = 0; i < coreTemperatures.Length; i++) {
   307         uint eax, edx;
   308         if (Ring0.RdmsrTx(
   309           IA32_THERM_STATUS_MSR, out eax, out edx,
   310             1UL << cpuid[i][0].Thread)) {
   311           // if reading is valid
   312           if ((eax & 0x80000000) != 0) {
   313             // get the dist from tjMax from bits 22:16
   314             float deltaT = ((eax & 0x007F0000) >> 16);
   315             float tjMax = coreTemperatures[i].Parameters[0].Value;
   316             float tSlope = coreTemperatures[i].Parameters[1].Value;
   317             coreTemperatures[i].Value = tjMax - tSlope * deltaT;
   318           } else {
   319             coreTemperatures[i].Value = null;
   320           }
   321         }
   322       }
   323 
   324       if (packageTemperature != null) {
   325         uint eax, edx;
   326         if (Ring0.RdmsrTx(
   327           IA32_PACKAGE_THERM_STATUS, out eax, out edx,
   328             1UL << cpuid[0][0].Thread)) {
   329           // get the dist from tjMax from bits 22:16
   330           float deltaT = ((eax & 0x007F0000) >> 16);
   331           float tjMax = packageTemperature.Parameters[0].Value;
   332           float tSlope = packageTemperature.Parameters[1].Value;
   333           packageTemperature.Value = tjMax - tSlope * deltaT;
   334         } else {
   335           packageTemperature.Value = null;
   336         }
   337       }
   338 
   339       if (HasTimeStampCounter && timeStampCounterMultiplier > 0) {
   340         double newBusClock = 0;
   341         uint eax, edx;
   342         for (int i = 0; i < coreClocks.Length; i++) {
   343           System.Threading.Thread.Sleep(1);
   344           if (Ring0.RdmsrTx(IA32_PERF_STATUS, out eax, out edx,
   345             1UL << cpuid[i][0].Thread)) {
   346             newBusClock =
   347               TimeStampCounterFrequency / timeStampCounterMultiplier;
   348             switch (microarchitecture) {
   349               case Microarchitecture.Nehalem: {
   350                   uint multiplier = eax & 0xff;
   351                   coreClocks[i].Value = (float)(multiplier * newBusClock);
   352                 } break;
   353               case Microarchitecture.SandyBridge:
   354               case Microarchitecture.IvyBridge:
   355               case Microarchitecture.Haswell: {
   356                   uint multiplier = (eax >> 8) & 0xff;
   357                   coreClocks[i].Value = (float)(multiplier * newBusClock);
   358                 } break;
   359               default: {
   360                   double multiplier =
   361                     ((eax >> 8) & 0x1f) + 0.5 * ((eax >> 14) & 1);
   362                   coreClocks[i].Value = (float)(multiplier * newBusClock);
   363                 } break;
   364             }
   365           } else {
   366             // if IA32_PERF_STATUS is not available, assume TSC frequency
   367             coreClocks[i].Value = (float)TimeStampCounterFrequency;
   368           }
   369         }
   370         if (newBusClock > 0) {
   371           this.busClock.Value = (float)newBusClock;
   372           ActivateSensor(this.busClock);
   373         }
   374       }
   375 
   376       if (powerSensors != null) {
   377         foreach (Sensor sensor in powerSensors) {
   378           if (sensor == null)
   379             continue;
   380 
   381           uint eax, edx;
   382           if (!Ring0.Rdmsr(energyStatusMSRs[sensor.Index], out eax, out edx))
   383             continue;
   384 
   385           DateTime time = DateTime.UtcNow;
   386           uint energyConsumed = eax;
   387           float deltaTime =
   388             (float)(time - lastEnergyTime[sensor.Index]).TotalSeconds;
   389           if (deltaTime < 0.01)
   390             continue;
   391 
   392           sensor.Value = energyUnitMultiplier * unchecked(
   393             energyConsumed - lastEnergyConsumed[sensor.Index]) / deltaTime;
   394           lastEnergyTime[sensor.Index] = time;
   395           lastEnergyConsumed[sensor.Index] = energyConsumed;
   396         }
   397       }
   398     }
   399   }
   400 }