Hardware/CPU/IntelCPU.cs
author StephaneLenclud
Thu, 18 Apr 2013 23:25:10 +0200
changeset 402 ded1323b61ee
parent 344 3145aadca3d2
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.
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
}