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