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