Hardware/CPU/IntelCPU.cs
author StephaneLenclud
Thu, 18 Apr 2013 23:25:10 +0200
changeset 402 ded1323b61ee
parent 344 3145aadca3d2
permissions -rw-r--r--
Front View plug-in does not init if no sensor added.
Fixing some format to make strings shorter.
Now trying to start SoundGraphAccess.exe process from same directory.
Packed mode now can display three sensors along with the current time.
     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 }