Hardware/CPU/IntelCPU.cs
author moel.mich
Sun, 08 May 2011 22:10:13 +0000
changeset 279 6bce967ba1b5
parent 250 c19d56a0bcad
child 306 e9127c00ada1
permissions -rw-r--r--
Fixed the bus and core clock reading on AMD family 10h model Ah CPUs. The new "Core Performance Boost" feature of these CPUs resulted in very low accuracy of the bus speed (and as a consequence also an inaccurate TSC multiplier). This fixed Issue 205.
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@195
    55
    private readonly Sensor[] coreClocks;
moel@195
    56
    private readonly Sensor busClock;
moel@63
    57
moel@219
    58
    private readonly Microarchitecture microarchitecture;
moel@219
    59
    private readonly double timeStampCounterMultiplier;
moel@79
    60
moel@1
    61
    private const uint IA32_THERM_STATUS_MSR = 0x019C;
moel@4
    62
    private const uint IA32_TEMPERATURE_TARGET = 0x01A2;
moel@44
    63
    private const uint IA32_PERF_STATUS = 0x0198;
moel@46
    64
    private const uint MSR_PLATFORM_INFO = 0xCE;
moel@1
    65
moel@69
    66
    private float[] Floats(float f) {
moel@69
    67
      float[] result = new float[coreCount];
moel@69
    68
      for (int i = 0; i < coreCount; i++)
moel@69
    69
        result[i] = f;
moel@69
    70
      return result;
moel@69
    71
    }
moel@69
    72
moel@249
    73
    private float[] GetTjMaxFromMSR() {
moel@249
    74
      uint eax, edx;
moel@249
    75
      float[] result = new float[coreCount];
moel@249
    76
      for (int i = 0; i < coreCount; i++) {
moel@249
    77
        if (Ring0.RdmsrTx(IA32_TEMPERATURE_TARGET, out eax,
moel@249
    78
          out edx, 1UL << cpuid[i][0].Thread)) {
moel@249
    79
          result[i] = (eax >> 16) & 0xFF;
moel@249
    80
        } else {
moel@249
    81
          result[i] = 100;
moel@249
    82
        }
moel@249
    83
      }
moel@249
    84
      return result;
moel@249
    85
    }
moel@249
    86
moel@191
    87
    public IntelCPU(int processorIndex, CPUID[][] cpuid, ISettings settings)
moel@191
    88
      : base(processorIndex, cpuid, settings) 
moel@191
    89
    {
moel@219
    90
      // set tjMax
moel@69
    91
      float[] tjMax;
moel@49
    92
      switch (family) {
moel@49
    93
        case 0x06: {
moel@49
    94
            switch (model) {
moel@219
    95
              case 0x0F: // Intel Core 2 (65nm)
moel@219
    96
                microarchitecture = Microarchitecture.Core;
moel@49
    97
                switch (stepping) {
moel@49
    98
                  case 0x06: // B2
moel@49
    99
                    switch (coreCount) {
moel@49
   100
                      case 2:
moel@69
   101
                        tjMax = Floats(80 + 10); break;
moel@49
   102
                      case 4:
moel@69
   103
                        tjMax = Floats(90 + 10); break;
moel@49
   104
                      default:
moel@69
   105
                        tjMax = Floats(85 + 10); break;
moel@49
   106
                    }
moel@69
   107
                    tjMax = Floats(80 + 10); break;
moel@49
   108
                  case 0x0B: // G0
moel@69
   109
                    tjMax = Floats(90 + 10); break;
moel@49
   110
                  case 0x0D: // M0
moel@69
   111
                    tjMax = Floats(85 + 10); break;
moel@49
   112
                  default:
moel@69
   113
                    tjMax = Floats(85 + 10); break;
moel@49
   114
                } break;
moel@219
   115
              case 0x17: // Intel Core 2 (45nm)
moel@219
   116
                microarchitecture = Microarchitecture.Core;
moel@69
   117
                tjMax = Floats(100); break;
moel@114
   118
              case 0x1C: // Intel Atom (45nm)
moel@219
   119
                microarchitecture = Microarchitecture.Atom;
moel@114
   120
                switch (stepping) {
moel@114
   121
                  case 0x02: // C0
moel@114
   122
                    tjMax = Floats(90); break;
moel@114
   123
                  case 0x0A: // A0, B0
moel@114
   124
                    tjMax = Floats(100); break;
moel@114
   125
                  default:
moel@114
   126
                    tjMax = Floats(90); break;
moel@191
   127
                } break;
moel@49
   128
              case 0x1A: // Intel Core i7 LGA1366 (45nm)
moel@49
   129
              case 0x1E: // Intel Core i5, i7 LGA1156 (45nm)
moel@249
   130
              case 0x1F: // Intel Core i5, i7 
moel@49
   131
              case 0x25: // Intel Core i3, i5, i7 LGA1156 (32nm)
moel@91
   132
              case 0x2C: // Intel Core i7 LGA1366 (32nm) 6 Core
moel@249
   133
              case 0x2E: // Intel Xeon Processor 7500 series
moel@219
   134
                microarchitecture = Microarchitecture.Nehalem;
moel@249
   135
                tjMax = GetTjMaxFromMSR();
moel@249
   136
                break;
moel@249
   137
              case 0x2A: // Intel Core i5, i7 2xxx LGA1155 (32nm)
moel@249
   138
              case 0x2D: // Next Generation Intel Xeon Processor
moel@249
   139
                microarchitecture = Microarchitecture.SandyBridge;
moel@249
   140
                tjMax = GetTjMaxFromMSR();
moel@49
   141
                break;
moel@49
   142
              default:
moel@219
   143
                microarchitecture = Microarchitecture.Unknown;
moel@219
   144
                tjMax = Floats(100); 
moel@219
   145
                break;
moel@49
   146
            }
moel@49
   147
          } break;
moel@264
   148
        case 0x0F: {
moel@264
   149
            switch (model) {
moel@264
   150
              case 0x00: // Pentium 4 (180nm)
moel@264
   151
              case 0x01: // Pentium 4 (130nm)
moel@264
   152
              case 0x02: // Pentium 4 (130nm)
moel@264
   153
              case 0x03: // Pentium 4, Celeron D (90nm)
moel@264
   154
              case 0x04: // Pentium 4, Pentium D, Celeron D (90nm)
moel@264
   155
              case 0x06: // Pentium 4, Pentium D, Celeron D (65nm)
moel@264
   156
                microarchitecture = Microarchitecture.NetBurst;
moel@264
   157
                tjMax = Floats(100); 
moel@264
   158
                break;
moel@264
   159
              default:
moel@264
   160
                microarchitecture = Microarchitecture.Unknown;
moel@264
   161
                tjMax = Floats(100);
moel@264
   162
                break;
moel@264
   163
            }
moel@264
   164
          } break;
moel@219
   165
        default:
moel@219
   166
          microarchitecture = Microarchitecture.Unknown;
moel@219
   167
          tjMax = Floats(100); 
moel@219
   168
          break;
moel@219
   169
      }
moel@219
   170
moel@219
   171
      // set timeStampCounterMultiplier
moel@219
   172
      switch (microarchitecture) {
moel@264
   173
        case Microarchitecture.NetBurst:
moel@219
   174
        case Microarchitecture.Atom:
moel@219
   175
        case Microarchitecture.Core: {
moel@219
   176
            uint eax, edx;
moel@236
   177
            if (Ring0.Rdmsr(IA32_PERF_STATUS, out eax, out edx)) {
moel@219
   178
              timeStampCounterMultiplier = 
moel@219
   179
                ((edx >> 8) & 0x1f) + 0.5 * ((edx >> 14) & 1);
moel@219
   180
            }
moel@219
   181
          } break;
moel@249
   182
        case Microarchitecture.Nehalem: 
moel@249
   183
        case Microarchitecture.SandyBridge: {
moel@219
   184
            uint eax, edx;
moel@236
   185
            if (Ring0.Rdmsr(MSR_PLATFORM_INFO, out eax, out edx)) {
moel@219
   186
              timeStampCounterMultiplier = (eax >> 8) & 0xff;
moel@219
   187
            }
moel@219
   188
          } break;
moel@264
   189
        default: {
moel@264
   190
            timeStampCounterMultiplier = 1;
moel@264
   191
            uint eax, edx;
moel@264
   192
            if (Ring0.Rdmsr(IA32_PERF_STATUS, out eax, out edx)) {
moel@264
   193
              timeStampCounterMultiplier =
moel@264
   194
                ((edx >> 8) & 0x1f) + 0.5 * ((edx >> 14) & 1);
moel@264
   195
            }
moel@264
   196
          } break;
moel@49
   197
      }
moel@1
   198
moel@44
   199
      // check if processor supports a digital thermal sensor
moel@191
   200
      if (cpuid[0][0].Data.GetLength(0) > 6 &&
moel@191
   201
        (cpuid[0][0].Data[6, 0] & 1) != 0) {
moel@44
   202
        coreTemperatures = new Sensor[coreCount];
moel@44
   203
        for (int i = 0; i < coreTemperatures.Length; i++) {
moel@134
   204
          coreTemperatures[i] = new Sensor(CoreString(i), i,
moel@195
   205
            SensorType.Temperature, this, new [] { 
moel@63
   206
              new ParameterDescription(
moel@122
   207
                "TjMax [°C]", "TjMax temperature of the core.\n" + 
moel@69
   208
                "Temperature = TjMax - TSlope * Value.", tjMax[i]), 
moel@122
   209
              new ParameterDescription("TSlope [°C]", 
moel@122
   210
                "Temperature slope of the digital thermal sensor.\n" + 
moel@165
   211
                "Temperature = TjMax - TSlope * Value.", 1)}, settings);
moel@155
   212
          ActivateSensor(coreTemperatures[i]);
moel@44
   213
        }
moel@44
   214
      } else {
moel@44
   215
        coreTemperatures = new Sensor[0];
moel@1
   216
      }
moel@49
   217
moel@191
   218
      busClock = new Sensor("Bus Speed", 0, SensorType.Clock, this, settings);
moel@44
   219
      coreClocks = new Sensor[coreCount];
moel@44
   220
      for (int i = 0; i < coreClocks.Length; i++) {
moel@49
   221
        coreClocks[i] =
moel@165
   222
          new Sensor(CoreString(i), i + 1, SensorType.Clock, this, settings);
moel@201
   223
        if (HasTimeStampCounter)
moel@79
   224
          ActivateSensor(coreClocks[i]);
moel@44
   225
      }
moel@191
   226
moel@191
   227
      Update();
moel@1
   228
    }
moel@1
   229
moel@191
   230
    protected override uint[] GetMSRs() {
moel@195
   231
      return new [] {
moel@191
   232
        MSR_PLATFORM_INFO,
moel@191
   233
        IA32_PERF_STATUS ,
moel@191
   234
        IA32_THERM_STATUS_MSR,
moel@191
   235
        IA32_TEMPERATURE_TARGET
moel@191
   236
      };
moel@1
   237
    }
moel@1
   238
moel@219
   239
    public override string GetReport() {
moel@219
   240
      StringBuilder r = new StringBuilder();
moel@219
   241
      r.Append(base.GetReport());
moel@219
   242
moel@264
   243
      r.Append("Microarchitecture: ");
moel@264
   244
      r.AppendLine(microarchitecture.ToString());
moel@219
   245
      r.Append("Time Stamp Counter Multiplier: ");
moel@219
   246
      r.AppendLine(timeStampCounterMultiplier.ToString(
moel@219
   247
        CultureInfo.InvariantCulture));
moel@219
   248
      r.AppendLine();
moel@219
   249
moel@219
   250
      return r.ToString();
moel@219
   251
    }
moel@219
   252
moel@191
   253
    public override void Update() {
moel@191
   254
      base.Update();
moel@1
   255
moel@1
   256
      for (int i = 0; i < coreTemperatures.Length; i++) {
moel@46
   257
        uint eax, edx;
moel@236
   258
        if (Ring0.RdmsrTx(
moel@191
   259
          IA32_THERM_STATUS_MSR, out eax, out edx,
moel@238
   260
            1UL << cpuid[i][0].Thread)) {
moel@1
   261
          // if reading is valid
moel@1
   262
          if ((eax & 0x80000000) != 0) {
moel@1
   263
            // get the dist from tjMax from bits 22:16
moel@63
   264
            float deltaT = ((eax & 0x007F0000) >> 16);
moel@63
   265
            float tjMax = coreTemperatures[i].Parameters[0].Value;
moel@63
   266
            float tSlope = coreTemperatures[i].Parameters[1].Value;
moel@63
   267
            coreTemperatures[i].Value = tjMax - tSlope * deltaT;
moel@24
   268
          } else {
moel@155
   269
            coreTemperatures[i].Value = null;
moel@1
   270
          }
moel@79
   271
        }
moel@24
   272
      }
moel@24
   273
moel@201
   274
      if (HasTimeStampCounter) {
moel@191
   275
        double newBusClock = 0;
moel@191
   276
        uint eax, edx;
moel@191
   277
        for (int i = 0; i < coreClocks.Length; i++) {
moel@191
   278
          System.Threading.Thread.Sleep(1);
moel@236
   279
          if (Ring0.RdmsrTx(IA32_PERF_STATUS, out eax, out edx,
moel@238
   280
            1UL << cpuid[i][0].Thread)) 
moel@219
   281
          {
moel@219
   282
            newBusClock = 
moel@219
   283
              TimeStampCounterFrequency / timeStampCounterMultiplier;
moel@250
   284
            switch (microarchitecture) {
moel@250
   285
              case Microarchitecture.Nehalem: {
moel@250
   286
                  uint multiplier = eax & 0xff;
moel@250
   287
                  coreClocks[i].Value = (float)(multiplier * newBusClock);
moel@250
   288
                } break;
moel@250
   289
              case Microarchitecture.SandyBridge: {
moel@250
   290
                  uint multiplier = (eax >> 8) & 0xff;
moel@250
   291
                  coreClocks[i].Value = (float)(multiplier * newBusClock);
moel@250
   292
                } break;
moel@250
   293
              default: {
moel@250
   294
                  double multiplier = 
moel@250
   295
                    ((eax >> 8) & 0x1f) + 0.5 * ((eax >> 14) & 1);
moel@250
   296
                  coreClocks[i].Value = (float)(multiplier * newBusClock);
moel@250
   297
                } break;
moel@250
   298
            }         
moel@219
   299
          } else { 
moel@201
   300
            // if IA32_PERF_STATUS is not available, assume TSC frequency
moel@201
   301
            coreClocks[i].Value = (float)TimeStampCounterFrequency;
moel@46
   302
          }
moel@44
   303
        }
moel@191
   304
        if (newBusClock > 0) {
moel@191
   305
          this.busClock.Value = (float)newBusClock;
moel@191
   306
          ActivateSensor(this.busClock);
moel@191
   307
        }
moel@44
   308
      }
moel@46
   309
    }
moel@191
   310
  }
moel@1
   311
}