Hardware/CPU/IntelCPU.cs
author moel.mich
Wed, 27 Jul 2011 18:27:16 +0000
changeset 317 1ccf99e620a9
parent 315 158ec57434e8
child 320 df3493f75225
permissions -rw-r--r--
Added support for Intel CPU power sensors (package and cores).
moel@1
     1
/*
moel@1
     2
  
moel@1
     3
  Version: MPL 1.1/GPL 2.0/LGPL 2.1
moel@1
     4
moel@1
     5
  The contents of this file are subject to the Mozilla Public License Version
moel@1
     6
  1.1 (the "License"); you may not use this file except in compliance with
moel@1
     7
  the License. You may obtain a copy of the License at
moel@1
     8
 
moel@1
     9
  http://www.mozilla.org/MPL/
moel@1
    10
moel@1
    11
  Software distributed under the License is distributed on an "AS IS" basis,
moel@1
    12
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
moel@1
    13
  for the specific language governing rights and limitations under the License.
moel@1
    14
moel@1
    15
  The Original Code is the Open Hardware Monitor code.
moel@1
    16
moel@1
    17
  The Initial Developer of the Original Code is 
moel@1
    18
  Michael Möller <m.moeller@gmx.ch>.
moel@264
    19
  Portions created by the Initial Developer are Copyright (C) 2009-2011
moel@1
    20
  the Initial Developer. All Rights Reserved.
moel@1
    21
moel@1
    22
  Contributor(s):
moel@1
    23
moel@1
    24
  Alternatively, the contents of this file may be used under the terms of
moel@1
    25
  either the GNU General Public License Version 2 or later (the "GPL"), or
moel@1
    26
  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
moel@1
    27
  in which case the provisions of the GPL or the LGPL are applicable instead
moel@1
    28
  of those above. If you wish to allow use of your version of this file only
moel@1
    29
  under the terms of either the GPL or the LGPL, and not to allow others to
moel@1
    30
  use your version of this file under the terms of the MPL, indicate your
moel@1
    31
  decision by deleting the provisions above and replace them with the notice
moel@1
    32
  and other provisions required by the GPL or the LGPL. If you do not delete
moel@1
    33
  the provisions above, a recipient may use your version of this file under
moel@1
    34
  the terms of any one of the MPL, the GPL or the LGPL.
moel@1
    35
 
moel@1
    36
*/
moel@1
    37
moel@1
    38
using System;
moel@219
    39
using System.Globalization;
moel@219
    40
using System.Text;
moel@1
    41
moel@1
    42
namespace OpenHardwareMonitor.Hardware.CPU {
moel@191
    43
  internal sealed class IntelCPU : GenericCPU {
moel@46
    44
moel@219
    45
    private enum Microarchitecture {
moel@219
    46
      Unknown,
moel@264
    47
      NetBurst,
moel@219
    48
      Core,
moel@219
    49
      Atom,
moel@249
    50
      Nehalem,
moel@249
    51
      SandyBridge
moel@219
    52
    }
moel@219
    53
moel@195
    54
    private readonly Sensor[] coreTemperatures;
moel@306
    55
    private readonly Sensor packageTemperature;
moel@195
    56
    private readonly Sensor[] coreClocks;
moel@195
    57
    private readonly Sensor busClock;
moel@317
    58
    private readonly Sensor packagePower;
moel@317
    59
    private readonly Sensor coresPower;
moel@63
    60
moel@219
    61
    private readonly Microarchitecture microarchitecture;
moel@219
    62
    private readonly double timeStampCounterMultiplier;
moel@79
    63
moel@1
    64
    private const uint IA32_THERM_STATUS_MSR = 0x019C;
moel@4
    65
    private const uint IA32_TEMPERATURE_TARGET = 0x01A2;
moel@44
    66
    private const uint IA32_PERF_STATUS = 0x0198;
moel@46
    67
    private const uint MSR_PLATFORM_INFO = 0xCE;
moel@306
    68
    private const uint IA32_PACKAGE_THERM_STATUS = 0x1B1;
moel@317
    69
    private const uint MSR_RAPL_POWER_UNIT = 0x606;
moel@317
    70
    private const uint MSR_PKG_ENERY_STATUS = 0x611;
moel@317
    71
    private const uint MSR_PP0_ENERY_STATUS = 0x639;
moel@317
    72
moel@317
    73
    private float energyUnitMultiplier = 0;
moel@317
    74
    private DateTime lastPackageTime;
moel@317
    75
    private uint lastPackageEnergyConsumed;
moel@317
    76
    private DateTime lastCoresTime;
moel@317
    77
    private uint lastCoresEnergyConsumed;
moel@317
    78
moel@317
    79
moel@1
    80
moel@69
    81
    private float[] Floats(float f) {
moel@69
    82
      float[] result = new float[coreCount];
moel@69
    83
      for (int i = 0; i < coreCount; i++)
moel@69
    84
        result[i] = f;
moel@69
    85
      return result;
moel@69
    86
    }
moel@69
    87
moel@249
    88
    private float[] GetTjMaxFromMSR() {
moel@249
    89
      uint eax, edx;
moel@249
    90
      float[] result = new float[coreCount];
moel@249
    91
      for (int i = 0; i < coreCount; i++) {
moel@249
    92
        if (Ring0.RdmsrTx(IA32_TEMPERATURE_TARGET, out eax,
moel@249
    93
          out edx, 1UL << cpuid[i][0].Thread)) {
moel@249
    94
          result[i] = (eax >> 16) & 0xFF;
moel@249
    95
        } else {
moel@249
    96
          result[i] = 100;
moel@249
    97
        }
moel@249
    98
      }
moel@249
    99
      return result;
moel@249
   100
    }
moel@249
   101
moel@191
   102
    public IntelCPU(int processorIndex, CPUID[][] cpuid, ISettings settings)
moel@191
   103
      : base(processorIndex, cpuid, settings) 
moel@191
   104
    {
moel@219
   105
      // set tjMax
moel@69
   106
      float[] tjMax;
moel@49
   107
      switch (family) {
moel@49
   108
        case 0x06: {
moel@49
   109
            switch (model) {
moel@219
   110
              case 0x0F: // Intel Core 2 (65nm)
moel@219
   111
                microarchitecture = Microarchitecture.Core;
moel@49
   112
                switch (stepping) {
moel@49
   113
                  case 0x06: // B2
moel@49
   114
                    switch (coreCount) {
moel@49
   115
                      case 2:
moel@69
   116
                        tjMax = Floats(80 + 10); break;
moel@49
   117
                      case 4:
moel@69
   118
                        tjMax = Floats(90 + 10); break;
moel@49
   119
                      default:
moel@69
   120
                        tjMax = Floats(85 + 10); break;
moel@49
   121
                    }
moel@69
   122
                    tjMax = Floats(80 + 10); break;
moel@49
   123
                  case 0x0B: // G0
moel@69
   124
                    tjMax = Floats(90 + 10); break;
moel@49
   125
                  case 0x0D: // M0
moel@69
   126
                    tjMax = Floats(85 + 10); break;
moel@49
   127
                  default:
moel@69
   128
                    tjMax = Floats(85 + 10); break;
moel@49
   129
                } break;
moel@219
   130
              case 0x17: // Intel Core 2 (45nm)
moel@219
   131
                microarchitecture = Microarchitecture.Core;
moel@69
   132
                tjMax = Floats(100); break;
moel@114
   133
              case 0x1C: // Intel Atom (45nm)
moel@219
   134
                microarchitecture = Microarchitecture.Atom;
moel@114
   135
                switch (stepping) {
moel@114
   136
                  case 0x02: // C0
moel@114
   137
                    tjMax = Floats(90); break;
moel@114
   138
                  case 0x0A: // A0, B0
moel@114
   139
                    tjMax = Floats(100); break;
moel@114
   140
                  default:
moel@114
   141
                    tjMax = Floats(90); break;
moel@191
   142
                } break;
moel@49
   143
              case 0x1A: // Intel Core i7 LGA1366 (45nm)
moel@49
   144
              case 0x1E: // Intel Core i5, i7 LGA1156 (45nm)
moel@249
   145
              case 0x1F: // Intel Core i5, i7 
moel@49
   146
              case 0x25: // Intel Core i3, i5, i7 LGA1156 (32nm)
moel@91
   147
              case 0x2C: // Intel Core i7 LGA1366 (32nm) 6 Core
moel@249
   148
              case 0x2E: // Intel Xeon Processor 7500 series
moel@219
   149
                microarchitecture = Microarchitecture.Nehalem;
moel@249
   150
                tjMax = GetTjMaxFromMSR();
moel@249
   151
                break;
moel@249
   152
              case 0x2A: // Intel Core i5, i7 2xxx LGA1155 (32nm)
moel@249
   153
              case 0x2D: // Next Generation Intel Xeon Processor
moel@249
   154
                microarchitecture = Microarchitecture.SandyBridge;
moel@249
   155
                tjMax = GetTjMaxFromMSR();
moel@49
   156
                break;
moel@49
   157
              default:
moel@219
   158
                microarchitecture = Microarchitecture.Unknown;
moel@219
   159
                tjMax = Floats(100); 
moel@219
   160
                break;
moel@49
   161
            }
moel@49
   162
          } break;
moel@264
   163
        case 0x0F: {
moel@264
   164
            switch (model) {
moel@264
   165
              case 0x00: // Pentium 4 (180nm)
moel@264
   166
              case 0x01: // Pentium 4 (130nm)
moel@264
   167
              case 0x02: // Pentium 4 (130nm)
moel@264
   168
              case 0x03: // Pentium 4, Celeron D (90nm)
moel@264
   169
              case 0x04: // Pentium 4, Pentium D, Celeron D (90nm)
moel@264
   170
              case 0x06: // Pentium 4, Pentium D, Celeron D (65nm)
moel@264
   171
                microarchitecture = Microarchitecture.NetBurst;
moel@264
   172
                tjMax = Floats(100); 
moel@264
   173
                break;
moel@264
   174
              default:
moel@264
   175
                microarchitecture = Microarchitecture.Unknown;
moel@264
   176
                tjMax = Floats(100);
moel@264
   177
                break;
moel@264
   178
            }
moel@264
   179
          } break;
moel@219
   180
        default:
moel@219
   181
          microarchitecture = Microarchitecture.Unknown;
moel@219
   182
          tjMax = Floats(100); 
moel@219
   183
          break;
moel@219
   184
      }
moel@219
   185
moel@219
   186
      // set timeStampCounterMultiplier
moel@219
   187
      switch (microarchitecture) {
moel@264
   188
        case Microarchitecture.NetBurst:
moel@219
   189
        case Microarchitecture.Atom:
moel@219
   190
        case Microarchitecture.Core: {
moel@219
   191
            uint eax, edx;
moel@236
   192
            if (Ring0.Rdmsr(IA32_PERF_STATUS, out eax, out edx)) {
moel@219
   193
              timeStampCounterMultiplier = 
moel@219
   194
                ((edx >> 8) & 0x1f) + 0.5 * ((edx >> 14) & 1);
moel@219
   195
            }
moel@219
   196
          } break;
moel@249
   197
        case Microarchitecture.Nehalem: 
moel@249
   198
        case Microarchitecture.SandyBridge: {
moel@219
   199
            uint eax, edx;
moel@236
   200
            if (Ring0.Rdmsr(MSR_PLATFORM_INFO, out eax, out edx)) {
moel@219
   201
              timeStampCounterMultiplier = (eax >> 8) & 0xff;
moel@219
   202
            }
moel@219
   203
          } break;
moel@264
   204
        default: {
moel@264
   205
            timeStampCounterMultiplier = 1;
moel@264
   206
            uint eax, edx;
moel@264
   207
            if (Ring0.Rdmsr(IA32_PERF_STATUS, out eax, out edx)) {
moel@264
   208
              timeStampCounterMultiplier =
moel@264
   209
                ((edx >> 8) & 0x1f) + 0.5 * ((edx >> 14) & 1);
moel@264
   210
            }
moel@264
   211
          } break;
moel@49
   212
      }
moel@1
   213
moel@306
   214
      // check if processor supports a digital thermal sensor at core level
moel@191
   215
      if (cpuid[0][0].Data.GetLength(0) > 6 &&
moel@306
   216
        (cpuid[0][0].Data[6, 0] & 1) != 0) 
moel@306
   217
      {
moel@44
   218
        coreTemperatures = new Sensor[coreCount];
moel@44
   219
        for (int i = 0; i < coreTemperatures.Length; i++) {
moel@134
   220
          coreTemperatures[i] = new Sensor(CoreString(i), i,
moel@195
   221
            SensorType.Temperature, this, new [] { 
moel@63
   222
              new ParameterDescription(
moel@306
   223
                "TjMax [°C]", "TjMax temperature of the core sensor.\n" + 
moel@69
   224
                "Temperature = TjMax - TSlope * Value.", tjMax[i]), 
moel@122
   225
              new ParameterDescription("TSlope [°C]", 
moel@122
   226
                "Temperature slope of the digital thermal sensor.\n" + 
moel@165
   227
                "Temperature = TjMax - TSlope * Value.", 1)}, settings);
moel@155
   228
          ActivateSensor(coreTemperatures[i]);
moel@44
   229
        }
moel@44
   230
      } else {
moel@44
   231
        coreTemperatures = new Sensor[0];
moel@1
   232
      }
moel@49
   233
moel@306
   234
      // check if processor supports a digital thermal sensor at package level
moel@306
   235
      if (cpuid[0][0].Data.GetLength(0) > 6 &&
moel@306
   236
        (cpuid[0][0].Data[6, 0] & 0x40) != 0) 
moel@306
   237
      {
moel@306
   238
          packageTemperature = new Sensor("CPU Package", 
moel@306
   239
            coreTemperatures.Length, SensorType.Temperature, this, new[] { 
moel@306
   240
              new ParameterDescription(
moel@306
   241
                "TjMax [°C]", "TjMax temperature of the package sensor.\n" + 
moel@306
   242
                "Temperature = TjMax - TSlope * Value.", tjMax[0]), 
moel@306
   243
              new ParameterDescription("TSlope [°C]", 
moel@306
   244
                "Temperature slope of the digital thermal sensor.\n" + 
moel@306
   245
                "Temperature = TjMax - TSlope * Value.", 1)}, settings);
moel@306
   246
        ActivateSensor(packageTemperature);
moel@306
   247
      } 
moel@306
   248
moel@191
   249
      busClock = new Sensor("Bus Speed", 0, SensorType.Clock, this, settings);
moel@44
   250
      coreClocks = new Sensor[coreCount];
moel@44
   251
      for (int i = 0; i < coreClocks.Length; i++) {
moel@49
   252
        coreClocks[i] =
moel@165
   253
          new Sensor(CoreString(i), i + 1, SensorType.Clock, this, settings);
moel@201
   254
        if (HasTimeStampCounter)
moel@79
   255
          ActivateSensor(coreClocks[i]);
moel@44
   256
      }
moel@191
   257
moel@317
   258
      if (microarchitecture == Microarchitecture.SandyBridge) {
moel@317
   259
        uint eax, edx;
moel@317
   260
        if (Ring0.Rdmsr(MSR_RAPL_POWER_UNIT, out eax, out edx))
moel@317
   261
          energyUnitMultiplier = 1.0f / (1 << (int)((eax >> 8) & 0x1FF));
moel@317
   262
moel@317
   263
moel@317
   264
        if (energyUnitMultiplier != 0 && 
moel@317
   265
          Ring0.Rdmsr(MSR_PKG_ENERY_STATUS, out eax, out edx)) 
moel@317
   266
        {
moel@317
   267
          lastPackageTime = DateTime.UtcNow;
moel@317
   268
          lastPackageEnergyConsumed = eax;
moel@317
   269
          packagePower = new Sensor("CPU Package", 0, SensorType.Power, this, 
moel@317
   270
            settings);          
moel@317
   271
          ActivateSensor(packagePower);
moel@317
   272
        }
moel@317
   273
moel@317
   274
        if (energyUnitMultiplier != 0 &&
moel@317
   275
          Ring0.Rdmsr(MSR_PP0_ENERY_STATUS, out eax, out edx)) 
moel@317
   276
        {
moel@317
   277
          lastCoresTime = DateTime.UtcNow;
moel@317
   278
          lastCoresEnergyConsumed = eax;
moel@317
   279
          coresPower = new Sensor("CPU Cores", 1, SensorType.Power, this,
moel@317
   280
            settings);
moel@317
   281
          ActivateSensor(coresPower);
moel@317
   282
        }
moel@317
   283
      }
moel@317
   284
moel@191
   285
      Update();
moel@1
   286
    }
moel@1
   287
moel@191
   288
    protected override uint[] GetMSRs() {
moel@195
   289
      return new [] {
moel@191
   290
        MSR_PLATFORM_INFO,
moel@191
   291
        IA32_PERF_STATUS ,
moel@191
   292
        IA32_THERM_STATUS_MSR,
moel@306
   293
        IA32_TEMPERATURE_TARGET,
moel@317
   294
        IA32_PACKAGE_THERM_STATUS,
moel@317
   295
        MSR_RAPL_POWER_UNIT,
moel@317
   296
        MSR_PKG_ENERY_STATUS,
moel@317
   297
        MSR_PP0_ENERY_STATUS
moel@191
   298
      };
moel@1
   299
    }
moel@1
   300
moel@219
   301
    public override string GetReport() {
moel@219
   302
      StringBuilder r = new StringBuilder();
moel@219
   303
      r.Append(base.GetReport());
moel@219
   304
moel@264
   305
      r.Append("Microarchitecture: ");
moel@264
   306
      r.AppendLine(microarchitecture.ToString());
moel@219
   307
      r.Append("Time Stamp Counter Multiplier: ");
moel@219
   308
      r.AppendLine(timeStampCounterMultiplier.ToString(
moel@219
   309
        CultureInfo.InvariantCulture));
moel@219
   310
      r.AppendLine();
moel@219
   311
moel@219
   312
      return r.ToString();
moel@219
   313
    }
moel@219
   314
moel@191
   315
    public override void Update() {
moel@191
   316
      base.Update();
moel@1
   317
moel@1
   318
      for (int i = 0; i < coreTemperatures.Length; i++) {
moel@46
   319
        uint eax, edx;
moel@236
   320
        if (Ring0.RdmsrTx(
moel@191
   321
          IA32_THERM_STATUS_MSR, out eax, out edx,
moel@238
   322
            1UL << cpuid[i][0].Thread)) {
moel@1
   323
          // if reading is valid
moel@1
   324
          if ((eax & 0x80000000) != 0) {
moel@1
   325
            // get the dist from tjMax from bits 22:16
moel@63
   326
            float deltaT = ((eax & 0x007F0000) >> 16);
moel@63
   327
            float tjMax = coreTemperatures[i].Parameters[0].Value;
moel@63
   328
            float tSlope = coreTemperatures[i].Parameters[1].Value;
moel@63
   329
            coreTemperatures[i].Value = tjMax - tSlope * deltaT;
moel@24
   330
          } else {
moel@155
   331
            coreTemperatures[i].Value = null;
moel@1
   332
          }
moel@79
   333
        }
moel@24
   334
      }
moel@24
   335
moel@306
   336
      if (packageTemperature != null) {
moel@306
   337
        uint eax, edx;
moel@306
   338
        if (Ring0.RdmsrTx(
moel@315
   339
          IA32_PACKAGE_THERM_STATUS, out eax, out edx,
moel@306
   340
            1UL << cpuid[0][0].Thread)) {
moel@306
   341
          // get the dist from tjMax from bits 22:16
moel@306
   342
          float deltaT = ((eax & 0x007F0000) >> 16);
moel@306
   343
          float tjMax = packageTemperature.Parameters[0].Value;
moel@306
   344
          float tSlope = packageTemperature.Parameters[1].Value;
moel@306
   345
          packageTemperature.Value = tjMax - tSlope * deltaT;
moel@306
   346
        } else {
moel@306
   347
          packageTemperature.Value = null;
moel@306
   348
        }
moel@306
   349
      }
moel@306
   350
moel@201
   351
      if (HasTimeStampCounter) {
moel@191
   352
        double newBusClock = 0;
moel@191
   353
        uint eax, edx;
moel@191
   354
        for (int i = 0; i < coreClocks.Length; i++) {
moel@191
   355
          System.Threading.Thread.Sleep(1);
moel@236
   356
          if (Ring0.RdmsrTx(IA32_PERF_STATUS, out eax, out edx,
moel@238
   357
            1UL << cpuid[i][0].Thread)) 
moel@219
   358
          {
moel@219
   359
            newBusClock = 
moel@219
   360
              TimeStampCounterFrequency / timeStampCounterMultiplier;
moel@250
   361
            switch (microarchitecture) {
moel@250
   362
              case Microarchitecture.Nehalem: {
moel@250
   363
                  uint multiplier = eax & 0xff;
moel@250
   364
                  coreClocks[i].Value = (float)(multiplier * newBusClock);
moel@250
   365
                } break;
moel@250
   366
              case Microarchitecture.SandyBridge: {
moel@250
   367
                  uint multiplier = (eax >> 8) & 0xff;
moel@250
   368
                  coreClocks[i].Value = (float)(multiplier * newBusClock);
moel@250
   369
                } break;
moel@250
   370
              default: {
moel@250
   371
                  double multiplier = 
moel@250
   372
                    ((eax >> 8) & 0x1f) + 0.5 * ((eax >> 14) & 1);
moel@250
   373
                  coreClocks[i].Value = (float)(multiplier * newBusClock);
moel@250
   374
                } break;
moel@250
   375
            }         
moel@219
   376
          } else { 
moel@201
   377
            // if IA32_PERF_STATUS is not available, assume TSC frequency
moel@201
   378
            coreClocks[i].Value = (float)TimeStampCounterFrequency;
moel@46
   379
          }
moel@44
   380
        }
moel@191
   381
        if (newBusClock > 0) {
moel@191
   382
          this.busClock.Value = (float)newBusClock;
moel@191
   383
          ActivateSensor(this.busClock);
moel@191
   384
        }
moel@44
   385
      }
moel@317
   386
moel@317
   387
moel@317
   388
      if (packagePower != null) {
moel@317
   389
        uint eax, edx;
moel@317
   390
        if (Ring0.Rdmsr(MSR_PKG_ENERY_STATUS, out eax, out edx)) {
moel@317
   391
          DateTime time = DateTime.UtcNow;    
moel@317
   392
          uint energyConsumed = eax;
moel@317
   393
          float deltaTime = (float)(time - lastPackageTime).TotalSeconds;
moel@317
   394
          if (deltaTime > 0.01) {
moel@317
   395
            packagePower.Value = energyUnitMultiplier * 
moel@317
   396
              unchecked(energyConsumed - lastPackageEnergyConsumed) / deltaTime;
moel@317
   397
            lastPackageTime = time;
moel@317
   398
            lastPackageEnergyConsumed = energyConsumed;
moel@317
   399
          }
moel@317
   400
        }         
moel@317
   401
      }
moel@317
   402
moel@317
   403
      if (coresPower != null) {
moel@317
   404
        uint eax, edx;
moel@317
   405
        if (Ring0.Rdmsr(MSR_PP0_ENERY_STATUS, out eax, out edx)) {
moel@317
   406
          DateTime time = DateTime.UtcNow;
moel@317
   407
          uint energyConsumed = eax;
moel@317
   408
          float deltaTime = (float)(time - lastCoresTime).TotalSeconds;
moel@317
   409
          if (deltaTime > 0.01) {
moel@317
   410
            coresPower.Value = energyUnitMultiplier *
moel@317
   411
              unchecked(energyConsumed - lastCoresEnergyConsumed) / deltaTime;
moel@317
   412
            lastCoresTime = time;
moel@317
   413
            lastCoresEnergyConsumed = energyConsumed;
moel@317
   414
          }
moel@317
   415
        }
moel@317
   416
      }
moel@46
   417
    }
moel@191
   418
  }
moel@1
   419
}