Hardware/CPU/IntelCPU.cs
author moel.mich
Sat, 03 Aug 2013 13:12:07 +0000
changeset 418 3bba187d41c2
parent 417 4865cf06a7fa
child 424 427fc32e589f
permissions -rw-r--r--
Changed the Intel core temperature reading to evaluate the "Reading Valid" bit 31 for package level sensors as well (undocumented).
     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 reading is valid
   309         if (Ring0.RdmsrTx(IA32_THERM_STATUS_MSR, out eax, out edx,
   310             1UL << cpuid[i][0].Thread) && (eax & 0x80000000) != 0) 
   311         {
   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       if (packageTemperature != null) {
   323         uint eax, edx;
   324         // if reading is valid
   325         if (Ring0.RdmsrTx(IA32_PACKAGE_THERM_STATUS, out eax, out edx,
   326             1UL << cpuid[0][0].Thread) && (eax & 0x80000000) != 0) 
   327         {
   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 }