Hardware/CPU/IntelCPU.cs
author moel.mich
Sat, 31 Dec 2011 17:31:04 +0000
changeset 324 c6ee430d6995
parent 320 df3493f75225
child 344 3145aadca3d2
permissions -rw-r--r--
Modified and extended version of the patch v4 by Roland Reinl (see Issue 256). Main differences to the original patch: DeviceIoControl refactorings removed, SmartAttribute is now descriptive only and does not hold any state, report is written as one 80 columns table, sensors are created only for meaningful values and without duplicates (remaining life, temperatures, host writes and reads). Also the current implementation should really preserve all the functionality of the old system. Additionally there is now a simple SMART devices emulation class (DebugSmart) that can be used in place of WindowsSmart for testing with reported data.
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
}