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