Hardware/CPU/IntelCPU.cs
author moel.mich
Thu, 11 Nov 2010 21:22:24 +0000
changeset 241 52007c404f32
parent 236 763675f19ff4
child 249 3b5be5dce071
permissions -rw-r--r--
Fixed a problem, where the MainForm location and size was lost when the application is started minimized and exited without ever showing the form. This caused MainForm_Load to be never called (location and size was not loaded), but the default size and location were still saved. The new implementation only saves the location and size when one of the two is changed.
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@1
    19
  Portions created by the Initial Developer are Copyright (C) 2009-2010
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@219
    47
      Core,
moel@219
    48
      Atom,
moel@219
    49
      Nehalem
moel@219
    50
    }
moel@219
    51
moel@195
    52
    private readonly Sensor[] coreTemperatures;
moel@195
    53
    private readonly Sensor[] coreClocks;
moel@195
    54
    private readonly Sensor busClock;
moel@63
    55
moel@219
    56
    private readonly Microarchitecture microarchitecture;
moel@219
    57
    private readonly double timeStampCounterMultiplier;
moel@79
    58
moel@1
    59
    private const uint IA32_THERM_STATUS_MSR = 0x019C;
moel@4
    60
    private const uint IA32_TEMPERATURE_TARGET = 0x01A2;
moel@44
    61
    private const uint IA32_PERF_STATUS = 0x0198;
moel@46
    62
    private const uint MSR_PLATFORM_INFO = 0xCE;
moel@1
    63
moel@69
    64
    private float[] Floats(float f) {
moel@69
    65
      float[] result = new float[coreCount];
moel@69
    66
      for (int i = 0; i < coreCount; i++)
moel@69
    67
        result[i] = f;
moel@69
    68
      return result;
moel@69
    69
    }
moel@69
    70
moel@191
    71
    public IntelCPU(int processorIndex, CPUID[][] cpuid, ISettings settings)
moel@191
    72
      : base(processorIndex, cpuid, settings) 
moel@191
    73
    {
moel@219
    74
      // set tjMax
moel@69
    75
      float[] tjMax;
moel@49
    76
      switch (family) {
moel@49
    77
        case 0x06: {
moel@49
    78
            switch (model) {
moel@219
    79
              case 0x0F: // Intel Core 2 (65nm)
moel@219
    80
                microarchitecture = Microarchitecture.Core;
moel@49
    81
                switch (stepping) {
moel@49
    82
                  case 0x06: // B2
moel@49
    83
                    switch (coreCount) {
moel@49
    84
                      case 2:
moel@69
    85
                        tjMax = Floats(80 + 10); break;
moel@49
    86
                      case 4:
moel@69
    87
                        tjMax = Floats(90 + 10); break;
moel@49
    88
                      default:
moel@69
    89
                        tjMax = Floats(85 + 10); break;
moel@49
    90
                    }
moel@69
    91
                    tjMax = Floats(80 + 10); break;
moel@49
    92
                  case 0x0B: // G0
moel@69
    93
                    tjMax = Floats(90 + 10); break;
moel@49
    94
                  case 0x0D: // M0
moel@69
    95
                    tjMax = Floats(85 + 10); break;
moel@49
    96
                  default:
moel@69
    97
                    tjMax = Floats(85 + 10); break;
moel@49
    98
                } break;
moel@219
    99
              case 0x17: // Intel Core 2 (45nm)
moel@219
   100
                microarchitecture = Microarchitecture.Core;
moel@69
   101
                tjMax = Floats(100); break;
moel@114
   102
              case 0x1C: // Intel Atom (45nm)
moel@219
   103
                microarchitecture = Microarchitecture.Atom;
moel@114
   104
                switch (stepping) {
moel@114
   105
                  case 0x02: // C0
moel@114
   106
                    tjMax = Floats(90); break;
moel@114
   107
                  case 0x0A: // A0, B0
moel@114
   108
                    tjMax = Floats(100); break;
moel@114
   109
                  default:
moel@114
   110
                    tjMax = Floats(90); break;
moel@191
   111
                } break;
moel@49
   112
              case 0x1A: // Intel Core i7 LGA1366 (45nm)
moel@49
   113
              case 0x1E: // Intel Core i5, i7 LGA1156 (45nm)
moel@49
   114
              case 0x25: // Intel Core i3, i5, i7 LGA1156 (32nm)
moel@91
   115
              case 0x2C: // Intel Core i7 LGA1366 (32nm) 6 Core
moel@219
   116
                microarchitecture = Microarchitecture.Nehalem;
moel@49
   117
                uint eax, edx;
moel@69
   118
                tjMax = new float[coreCount];
moel@69
   119
                for (int i = 0; i < coreCount; i++) {
moel@236
   120
                  if (Ring0.RdmsrTx(IA32_TEMPERATURE_TARGET, out eax,
moel@238
   121
                    out edx, 1UL << cpuid[i][0].Thread)) {
moel@69
   122
                    tjMax[i] = (eax >> 16) & 0xFF;
moel@69
   123
                  } else {
moel@69
   124
                    tjMax[i] = 100;
moel@69
   125
                  }
moel@219
   126
                }                
moel@49
   127
                break;
moel@49
   128
              default:
moel@219
   129
                microarchitecture = Microarchitecture.Unknown;
moel@219
   130
                tjMax = Floats(100); 
moel@219
   131
                break;
moel@49
   132
            }
moel@49
   133
          } break;
moel@219
   134
        default:
moel@219
   135
          microarchitecture = Microarchitecture.Unknown;
moel@219
   136
          tjMax = Floats(100); 
moel@219
   137
          break;
moel@219
   138
      }
moel@219
   139
moel@219
   140
      // set timeStampCounterMultiplier
moel@219
   141
      switch (microarchitecture) {
moel@219
   142
        case Microarchitecture.Atom:
moel@219
   143
        case Microarchitecture.Core: {
moel@219
   144
            uint eax, edx;
moel@236
   145
            if (Ring0.Rdmsr(IA32_PERF_STATUS, out eax, out edx)) {
moel@219
   146
              timeStampCounterMultiplier = 
moel@219
   147
                ((edx >> 8) & 0x1f) + 0.5 * ((edx >> 14) & 1);
moel@219
   148
            }
moel@219
   149
          } break;
moel@219
   150
        case Microarchitecture.Nehalem: {
moel@219
   151
            uint eax, edx;
moel@236
   152
            if (Ring0.Rdmsr(MSR_PLATFORM_INFO, out eax, out edx)) {
moel@219
   153
              timeStampCounterMultiplier = (eax >> 8) & 0xff;
moel@219
   154
            }
moel@219
   155
          } break;
moel@219
   156
        default:
moel@219
   157
          timeStampCounterMultiplier = 1;
moel@219
   158
          break;
moel@49
   159
      }
moel@1
   160
moel@44
   161
      // check if processor supports a digital thermal sensor
moel@191
   162
      if (cpuid[0][0].Data.GetLength(0) > 6 &&
moel@191
   163
        (cpuid[0][0].Data[6, 0] & 1) != 0) {
moel@44
   164
        coreTemperatures = new Sensor[coreCount];
moel@44
   165
        for (int i = 0; i < coreTemperatures.Length; i++) {
moel@134
   166
          coreTemperatures[i] = new Sensor(CoreString(i), i,
moel@195
   167
            SensorType.Temperature, this, new [] { 
moel@63
   168
              new ParameterDescription(
moel@122
   169
                "TjMax [°C]", "TjMax temperature of the core.\n" + 
moel@69
   170
                "Temperature = TjMax - TSlope * Value.", tjMax[i]), 
moel@122
   171
              new ParameterDescription("TSlope [°C]", 
moel@122
   172
                "Temperature slope of the digital thermal sensor.\n" + 
moel@165
   173
                "Temperature = TjMax - TSlope * Value.", 1)}, settings);
moel@155
   174
          ActivateSensor(coreTemperatures[i]);
moel@44
   175
        }
moel@44
   176
      } else {
moel@44
   177
        coreTemperatures = new Sensor[0];
moel@1
   178
      }
moel@49
   179
moel@191
   180
      busClock = new Sensor("Bus Speed", 0, SensorType.Clock, this, settings);
moel@44
   181
      coreClocks = new Sensor[coreCount];
moel@44
   182
      for (int i = 0; i < coreClocks.Length; i++) {
moel@49
   183
        coreClocks[i] =
moel@165
   184
          new Sensor(CoreString(i), i + 1, SensorType.Clock, this, settings);
moel@201
   185
        if (HasTimeStampCounter)
moel@79
   186
          ActivateSensor(coreClocks[i]);
moel@44
   187
      }
moel@191
   188
moel@191
   189
      Update();
moel@1
   190
    }
moel@1
   191
moel@191
   192
    protected override uint[] GetMSRs() {
moel@195
   193
      return new [] {
moel@191
   194
        MSR_PLATFORM_INFO,
moel@191
   195
        IA32_PERF_STATUS ,
moel@191
   196
        IA32_THERM_STATUS_MSR,
moel@191
   197
        IA32_TEMPERATURE_TARGET
moel@191
   198
      };
moel@1
   199
    }
moel@1
   200
moel@219
   201
    public override string GetReport() {
moel@219
   202
      StringBuilder r = new StringBuilder();
moel@219
   203
      r.Append(base.GetReport());
moel@219
   204
moel@219
   205
      r.Append("Time Stamp Counter Multiplier: ");
moel@219
   206
      r.AppendLine(timeStampCounterMultiplier.ToString(
moel@219
   207
        CultureInfo.InvariantCulture));
moel@219
   208
      r.AppendLine();
moel@219
   209
moel@219
   210
      return r.ToString();
moel@219
   211
    }
moel@219
   212
moel@191
   213
    public override void Update() {
moel@191
   214
      base.Update();
moel@1
   215
moel@1
   216
      for (int i = 0; i < coreTemperatures.Length; i++) {
moel@46
   217
        uint eax, edx;
moel@236
   218
        if (Ring0.RdmsrTx(
moel@191
   219
          IA32_THERM_STATUS_MSR, out eax, out edx,
moel@238
   220
            1UL << cpuid[i][0].Thread)) {
moel@1
   221
          // if reading is valid
moel@1
   222
          if ((eax & 0x80000000) != 0) {
moel@1
   223
            // get the dist from tjMax from bits 22:16
moel@63
   224
            float deltaT = ((eax & 0x007F0000) >> 16);
moel@63
   225
            float tjMax = coreTemperatures[i].Parameters[0].Value;
moel@63
   226
            float tSlope = coreTemperatures[i].Parameters[1].Value;
moel@63
   227
            coreTemperatures[i].Value = tjMax - tSlope * deltaT;
moel@24
   228
          } else {
moel@155
   229
            coreTemperatures[i].Value = null;
moel@1
   230
          }
moel@79
   231
        }
moel@24
   232
      }
moel@24
   233
moel@201
   234
      if (HasTimeStampCounter) {
moel@191
   235
        double newBusClock = 0;
moel@191
   236
        uint eax, edx;
moel@191
   237
        for (int i = 0; i < coreClocks.Length; i++) {
moel@191
   238
          System.Threading.Thread.Sleep(1);
moel@236
   239
          if (Ring0.RdmsrTx(IA32_PERF_STATUS, out eax, out edx,
moel@238
   240
            1UL << cpuid[i][0].Thread)) 
moel@219
   241
          {
moel@219
   242
            newBusClock = 
moel@219
   243
              TimeStampCounterFrequency / timeStampCounterMultiplier;
moel@219
   244
            if (microarchitecture == Microarchitecture.Nehalem) {
moel@219
   245
              uint multiplier = eax & 0xff;
moel@219
   246
              coreClocks[i].Value = (float)(multiplier * newBusClock);
moel@219
   247
            } else {
moel@219
   248
              double multiplier = ((eax >> 8) & 0x1f) + 0.5 * ((eax >> 14) & 1);
moel@219
   249
              coreClocks[i].Value = (float)(multiplier * newBusClock);
moel@219
   250
            }            
moel@219
   251
          } else { 
moel@201
   252
            // if IA32_PERF_STATUS is not available, assume TSC frequency
moel@201
   253
            coreClocks[i].Value = (float)TimeStampCounterFrequency;
moel@46
   254
          }
moel@44
   255
        }
moel@191
   256
        if (newBusClock > 0) {
moel@191
   257
          this.busClock.Value = (float)newBusClock;
moel@191
   258
          ActivateSensor(this.busClock);
moel@191
   259
        }
moel@44
   260
      }
moel@46
   261
    }
moel@191
   262
  }
moel@1
   263
}