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