Hardware/CPU/IntelCPU.cs
author moel.mich
Tue, 25 May 2010 18:57:28 +0000
changeset 127 76aaf45a01c7
parent 114 69dfa910e628
child 134 8b3b9b2e28e5
permissions -rw-r--r--
Added a workaround for the "You must keep the stream open for the lifetime of the Image." problem of the Image.FromStream method. This also reduced the overall memory usage (private working set).
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@1
    39
using System.Collections.Generic;
moel@1
    40
using System.Drawing;
moel@24
    41
using System.Diagnostics;
moel@79
    42
using System.Globalization;
moel@1
    43
using System.Reflection;
moel@63
    44
using System.Runtime.InteropServices;
moel@63
    45
using System.Threading;
moel@1
    46
using System.Text;
moel@1
    47
moel@1
    48
namespace OpenHardwareMonitor.Hardware.CPU {
moel@31
    49
  public class IntelCPU : Hardware, IHardware {
moel@1
    50
moel@100
    51
    private int processorIndex;
moel@90
    52
    private CPUID[][] cpuid;
moel@90
    53
    private int coreCount;
moel@90
    54
    
moel@1
    55
    private string name;
moel@1
    56
    private Image icon;
moel@1
    57
moel@46
    58
    private uint family;
moel@46
    59
    private uint model;
moel@46
    60
    private uint stepping;
moel@46
    61
moel@1
    62
    private Sensor[] coreTemperatures;
moel@63
    63
moel@24
    64
    private Sensor totalLoad;
moel@24
    65
    private Sensor[] coreLoads;
moel@44
    66
    private Sensor[] coreClocks;
moel@90
    67
    private Sensor busClock;    
moel@79
    68
    private bool hasTSC;
moel@79
    69
    private bool invariantTSC;    
moel@79
    70
    private double estimatedMaxClock;
moel@79
    71
moel@26
    72
    private CPULoad cpuLoad;
moel@44
    73
moel@79
    74
    private ulong lastTimeStampCount;    
moel@44
    75
    private long lastTime;
moel@79
    76
    private uint maxNehalemMultiplier = 0;    
moel@26
    77
    
moel@1
    78
    private const uint IA32_THERM_STATUS_MSR = 0x019C;
moel@4
    79
    private const uint IA32_TEMPERATURE_TARGET = 0x01A2;
moel@44
    80
    private const uint IA32_PERF_STATUS = 0x0198;
moel@46
    81
    private const uint MSR_PLATFORM_INFO = 0xCE;
moel@1
    82
moel@49
    83
    private string CoreString(int i) {
moel@49
    84
      if (coreCount == 1)
moel@49
    85
        return "CPU Core";
moel@49
    86
      else
moel@49
    87
        return "CPU Core #" + (i + 1);
moel@49
    88
    }
moel@49
    89
moel@69
    90
    private float[] Floats(float f) {
moel@69
    91
      float[] result = new float[coreCount];
moel@69
    92
      for (int i = 0; i < coreCount; i++)
moel@69
    93
        result[i] = f;
moel@69
    94
      return result;
moel@69
    95
    }
moel@69
    96
moel@100
    97
    public IntelCPU(int processorIndex, CPUID[][] cpuid) {
moel@90
    98
moel@100
    99
      this.processorIndex = processorIndex;
moel@90
   100
      this.cpuid = cpuid;
moel@90
   101
      this.coreCount = cpuid.Length;
moel@90
   102
      this.name = cpuid[0][0].Name;
moel@1
   103
      this.icon = Utilities.EmbeddedResources.GetImage("cpu.png");
moel@46
   104
moel@90
   105
      this.family = cpuid[0][0].Family;
moel@90
   106
      this.model = cpuid[0][0].Model;
moel@90
   107
      this.stepping = cpuid[0][0].Stepping;
moel@63
   108
moel@69
   109
      float[] tjMax;
moel@49
   110
      switch (family) {
moel@49
   111
        case 0x06: {
moel@49
   112
            switch (model) {
moel@49
   113
              case 0x0F: // Intel Core (65nm)
moel@49
   114
                switch (stepping) {
moel@49
   115
                  case 0x06: // B2
moel@49
   116
                    switch (coreCount) {
moel@49
   117
                      case 2:
moel@69
   118
                        tjMax = Floats(80 + 10); break;
moel@49
   119
                      case 4:
moel@69
   120
                        tjMax = Floats(90 + 10); break;
moel@49
   121
                      default:
moel@69
   122
                        tjMax = Floats(85 + 10); break;
moel@49
   123
                    }
moel@69
   124
                    tjMax = Floats(80 + 10); break;
moel@49
   125
                  case 0x0B: // G0
moel@69
   126
                    tjMax = Floats(90 + 10); break;
moel@49
   127
                  case 0x0D: // M0
moel@69
   128
                    tjMax = Floats(85 + 10); break;
moel@49
   129
                  default:
moel@69
   130
                    tjMax = Floats(85 + 10); break;
moel@49
   131
                } break;
moel@49
   132
              case 0x17: // Intel Core (45nm)
moel@69
   133
                tjMax = Floats(100); break;
moel@114
   134
              case 0x1C: // Intel Atom (45nm)
moel@114
   135
                switch (stepping) {
moel@114
   136
                  case 0x02: // C0
moel@114
   137
                    tjMax = Floats(90); break;
moel@114
   138
                  case 0x0A: // A0, B0
moel@114
   139
                    tjMax = Floats(100); break;
moel@114
   140
                  default:
moel@114
   141
                    tjMax = Floats(90); break;
moel@114
   142
                } break;                
moel@49
   143
              case 0x1A: // Intel Core i7 LGA1366 (45nm)
moel@49
   144
              case 0x1E: // Intel Core i5, i7 LGA1156 (45nm)
moel@49
   145
              case 0x25: // Intel Core i3, i5, i7 LGA1156 (32nm)
moel@91
   146
              case 0x2C: // Intel Core i7 LGA1366 (32nm) 6 Core
moel@49
   147
                uint eax, edx;
moel@69
   148
                tjMax = new float[coreCount];
moel@69
   149
                for (int i = 0; i < coreCount; i++) {
moel@69
   150
                  if (WinRing0.RdmsrTx(IA32_TEMPERATURE_TARGET, out eax,
moel@90
   151
                    out edx, (UIntPtr)(1L << cpuid[i][0].Thread)))
moel@69
   152
                  {
moel@69
   153
                    tjMax[i] = (eax >> 16) & 0xFF;
moel@69
   154
                  } else {
moel@69
   155
                    tjMax[i] = 100;
moel@69
   156
                  }
moel@49
   157
                }
moel@49
   158
                if (WinRing0.Rdmsr(MSR_PLATFORM_INFO, out eax, out edx)) {
moel@49
   159
                  maxNehalemMultiplier = (eax >> 8) & 0xff;
moel@49
   160
                }
moel@49
   161
                break;
moel@49
   162
              default:
moel@69
   163
                tjMax = Floats(100); break;
moel@49
   164
            }
moel@49
   165
          } break;
moel@69
   166
        default: tjMax = Floats(100); break;
moel@49
   167
      }
moel@1
   168
moel@44
   169
      // check if processor supports a digital thermal sensor
moel@90
   170
      if (cpuid[0][0].Data.GetLength(0) > 6 && 
moel@90
   171
        (cpuid[0][0].Data[6, 0] & 1) != 0) 
moel@90
   172
      {
moel@44
   173
        coreTemperatures = new Sensor[coreCount];
moel@44
   174
        for (int i = 0; i < coreTemperatures.Length; i++) {
moel@69
   175
          coreTemperatures[i] = new Sensor(CoreString(i), i, tjMax[i],
moel@63
   176
            SensorType.Temperature, this, new ParameterDescription[] { 
moel@63
   177
              new ParameterDescription(
moel@122
   178
                "TjMax [°C]", "TjMax temperature of the core.\n" + 
moel@69
   179
                "Temperature = TjMax - TSlope * Value.", tjMax[i]), 
moel@122
   180
              new ParameterDescription("TSlope [°C]", 
moel@122
   181
                "Temperature slope of the digital thermal sensor.\n" + 
moel@63
   182
                "Temperature = TjMax - TSlope * Value.", 1)});
moel@44
   183
        }
moel@44
   184
      } else {
moel@44
   185
        coreTemperatures = new Sensor[0];
moel@1
   186
      }
moel@49
   187
moel@49
   188
      if (coreCount > 1)
moel@49
   189
        totalLoad = new Sensor("CPU Total", 0, SensorType.Load, this);
moel@49
   190
      else
moel@49
   191
        totalLoad = null;
moel@24
   192
      coreLoads = new Sensor[coreCount];
moel@49
   193
      for (int i = 0; i < coreLoads.Length; i++)
moel@49
   194
        coreLoads[i] = new Sensor(CoreString(i), i + 1,
moel@44
   195
          SensorType.Load, this);     
moel@90
   196
      cpuLoad = new CPULoad(cpuid);
moel@26
   197
      if (cpuLoad.IsAvailable) {
moel@26
   198
        foreach (Sensor sensor in coreLoads)
moel@26
   199
          ActivateSensor(sensor);
moel@49
   200
        if (totalLoad != null)
moel@49
   201
          ActivateSensor(totalLoad);
moel@26
   202
      }
moel@26
   203
moel@79
   204
      // check if processor has TSC
moel@90
   205
      if (cpuid[0][0].Data.GetLength(0) > 1 
moel@90
   206
        && (cpuid[0][0].Data[1, 3] & 0x10) != 0)
moel@79
   207
        hasTSC = true;
moel@79
   208
      else
moel@79
   209
        hasTSC = false; 
moel@79
   210
moel@79
   211
      // check if processor supports invariant TSC 
moel@90
   212
      if (cpuid[0][0].ExtData.GetLength(0) > 7 
moel@90
   213
        && (cpuid[0][0].ExtData[7, 3] & 0x100) != 0)
moel@79
   214
        invariantTSC = true;
moel@79
   215
      else
moel@79
   216
        invariantTSC = false;
moel@79
   217
moel@79
   218
      // preload the function
moel@79
   219
      EstimateMaxClock(0); 
moel@79
   220
      EstimateMaxClock(0); 
moel@79
   221
moel@79
   222
      // estimate the max clock in MHz      
moel@97
   223
      List<double> estimatedMaxClocks = new List<double>(3);
moel@97
   224
      for (int i = 0; i < 3; i++)
moel@97
   225
        estimatedMaxClocks.Add(1e-6 * EstimateMaxClock(0.025));
moel@97
   226
      estimatedMaxClocks.Sort();
moel@97
   227
      estimatedMaxClock = estimatedMaxClocks[1];
moel@79
   228
moel@79
   229
      lastTimeStampCount = 0;
moel@44
   230
      lastTime = 0;
moel@44
   231
      busClock = new Sensor("Bus Speed", 0, SensorType.Clock, this);      
moel@44
   232
      coreClocks = new Sensor[coreCount];
moel@44
   233
      for (int i = 0; i < coreClocks.Length; i++) {
moel@49
   234
        coreClocks[i] =
moel@49
   235
          new Sensor(CoreString(i), i + 1, SensorType.Clock, this);
moel@79
   236
        if (hasTSC)
moel@79
   237
          ActivateSensor(coreClocks[i]);
moel@44
   238
      }
moel@44
   239
      
moel@1
   240
      Update();                   
moel@1
   241
    }
moel@1
   242
moel@110
   243
    public override string Name {
moel@1
   244
      get { return name; }
moel@1
   245
    }
moel@1
   246
moel@110
   247
    public override Identifier Identifier {
moel@109
   248
      get { return new Identifier("intelcpu", processorIndex.ToString()); }
moel@1
   249
    }
moel@1
   250
moel@110
   251
    public override Image Icon {
moel@1
   252
      get { return icon; }
moel@1
   253
    }
moel@1
   254
moel@90
   255
    private void AppendMSRData(StringBuilder r, uint msr, int thread) {
moel@49
   256
      uint eax, edx;
moel@90
   257
      if (WinRing0.RdmsrTx(msr, out eax, out edx, (UIntPtr)(1L << thread))) {
moel@49
   258
        r.Append(" ");
moel@49
   259
        r.Append((msr).ToString("X8"));
moel@49
   260
        r.Append("  ");
moel@49
   261
        r.Append((edx).ToString("X8"));
moel@49
   262
        r.Append("  ");
moel@49
   263
        r.Append((eax).ToString("X8"));
moel@49
   264
        r.AppendLine();
moel@49
   265
      }
moel@49
   266
    }
moel@49
   267
moel@110
   268
    public override string GetReport() {
moel@5
   269
      StringBuilder r = new StringBuilder();
moel@5
   270
moel@5
   271
      r.AppendLine("Intel CPU");
moel@5
   272
      r.AppendLine();
moel@5
   273
      r.AppendFormat("Name: {0}{1}", name, Environment.NewLine);
moel@63
   274
      r.AppendFormat("Number of Cores: {0}{1}", coreCount, 
moel@22
   275
        Environment.NewLine);
moel@90
   276
      r.AppendFormat("Threads per Core: {0}{1}", cpuid[0].Length,
moel@90
   277
        Environment.NewLine);     
moel@79
   278
      r.AppendLine("TSC: " + 
moel@79
   279
        (hasTSC ? (invariantTSC ? "Invariant" : "Not Invariant") : "None"));
moel@79
   280
      r.AppendLine(string.Format(CultureInfo.InvariantCulture, 
moel@79
   281
        "Timer Frequency: {0} MHz", Stopwatch.Frequency * 1e-6));
moel@79
   282
      r.AppendLine(string.Format(CultureInfo.InvariantCulture,
moel@79
   283
        "Max Clock: {0} MHz", Math.Round(estimatedMaxClock * 100) * 0.01));
moel@5
   284
      r.AppendLine();
moel@5
   285
moel@90
   286
      for (int i = 0; i < cpuid.Length; i++) {
moel@49
   287
        r.AppendLine("MSR Core #" + (i + 1));
moel@49
   288
        r.AppendLine();
moel@49
   289
        r.AppendLine(" MSR       EDX       EAX");
moel@90
   290
        AppendMSRData(r, MSR_PLATFORM_INFO, cpuid[i][0].Thread);
moel@90
   291
        AppendMSRData(r, IA32_PERF_STATUS, cpuid[i][0].Thread);
moel@90
   292
        AppendMSRData(r, IA32_THERM_STATUS_MSR, cpuid[i][0].Thread);
moel@90
   293
        AppendMSRData(r, IA32_TEMPERATURE_TARGET, cpuid[i][0].Thread);
moel@49
   294
        r.AppendLine();
moel@49
   295
      }
moel@49
   296
moel@5
   297
      return r.ToString();
moel@1
   298
    }
moel@1
   299
moel@79
   300
    private double EstimateMaxClock(double timeWindow) {
moel@79
   301
      long ticks = (long)(timeWindow * Stopwatch.Frequency);
moel@79
   302
      uint lsbBegin, msbBegin, lsbEnd, msbEnd; 
moel@79
   303
      
moel@79
   304
      Thread.BeginThreadAffinity();
moel@97
   305
      long timeBegin = Stopwatch.GetTimestamp() + 
moel@97
   306
        (long)Math.Ceiling(0.001 * ticks);
moel@79
   307
      long timeEnd = timeBegin + ticks;      
moel@79
   308
      while (Stopwatch.GetTimestamp() < timeBegin) { }
moel@79
   309
      WinRing0.Rdtsc(out lsbBegin, out msbBegin);
moel@79
   310
      while (Stopwatch.GetTimestamp() < timeEnd) { }
moel@79
   311
      WinRing0.Rdtsc(out lsbEnd, out msbEnd);
moel@79
   312
      Thread.EndThreadAffinity();
moel@79
   313
moel@79
   314
      ulong countBegin = ((ulong)msbBegin << 32) | lsbBegin;
moel@79
   315
      ulong countEnd = ((ulong)msbEnd << 32) | lsbEnd;
moel@79
   316
moel@79
   317
      return (((double)(countEnd - countBegin)) * Stopwatch.Frequency) / 
moel@79
   318
        (timeEnd - timeBegin);
moel@79
   319
    }
moel@79
   320
moel@110
   321
    public override void Update() {      
moel@1
   322
      for (int i = 0; i < coreTemperatures.Length; i++) {
moel@46
   323
        uint eax, edx;
moel@46
   324
        if (WinRing0.RdmsrTx(
moel@90
   325
          IA32_THERM_STATUS_MSR, out eax, out edx, 
moel@90
   326
            (UIntPtr)(1L << cpuid[i][0].Thread))) {
moel@1
   327
          // if reading is valid
moel@1
   328
          if ((eax & 0x80000000) != 0) {
moel@1
   329
            // get the dist from tjMax from bits 22:16
moel@63
   330
            float deltaT = ((eax & 0x007F0000) >> 16);
moel@63
   331
            float tjMax = coreTemperatures[i].Parameters[0].Value;
moel@63
   332
            float tSlope = coreTemperatures[i].Parameters[1].Value;
moel@63
   333
            coreTemperatures[i].Value = tjMax - tSlope * deltaT;
moel@24
   334
            ActivateSensor(coreTemperatures[i]);
moel@24
   335
          } else {
moel@24
   336
            DeactivateSensor(coreTemperatures[i]);
moel@1
   337
          }
moel@79
   338
        }
moel@24
   339
      }
moel@24
   340
moel@26
   341
      if (cpuLoad.IsAvailable) {
moel@26
   342
        cpuLoad.Update();
moel@26
   343
        for (int i = 0; i < coreLoads.Length; i++)
moel@26
   344
          coreLoads[i].Value = cpuLoad.GetCoreLoad(i);
moel@49
   345
        if (totalLoad != null)
moel@49
   346
          totalLoad.Value = cpuLoad.GetTotalLoad();
moel@24
   347
      }
moel@79
   348
moel@79
   349
      if (hasTSC) {
moel@79
   350
        uint lsb, msb;
moel@79
   351
        WinRing0.RdtscTx(out lsb, out msb, (UIntPtr)1);
moel@79
   352
        long time = Stopwatch.GetTimestamp();
moel@79
   353
        ulong timeStampCount = ((ulong)msb << 32) | lsb;
moel@79
   354
        double delta = ((double)(time - lastTime)) / Stopwatch.Frequency;
moel@79
   355
        if (delta > 0.5) {
moel@79
   356
          double maxClock;
moel@79
   357
          if (invariantTSC)
moel@79
   358
            maxClock = (timeStampCount - lastTimeStampCount) / (1e6 * delta);
moel@79
   359
          else
moel@79
   360
            maxClock = estimatedMaxClock;
moel@79
   361
moel@79
   362
          double busClock = 0;
moel@79
   363
          uint eax, edx;
moel@79
   364
          for (int i = 0; i < coreClocks.Length; i++) {
moel@79
   365
            System.Threading.Thread.Sleep(1);
moel@79
   366
            if (WinRing0.RdmsrTx(IA32_PERF_STATUS, out eax, out edx,
moel@90
   367
              (UIntPtr)(1L << cpuid[i][0].Thread))) {
moel@79
   368
              if (maxNehalemMultiplier > 0) { // Core i3, i5, i7
moel@79
   369
                uint nehalemMultiplier = eax & 0xff;
moel@79
   370
                coreClocks[i].Value =
moel@79
   371
                  (float)(nehalemMultiplier * maxClock / maxNehalemMultiplier);
moel@79
   372
                busClock = (float)(maxClock / maxNehalemMultiplier);
moel@79
   373
              } else { // Core 2
moel@79
   374
                uint multiplier = (eax >> 8) & 0x1f;
moel@79
   375
                uint maxMultiplier = (edx >> 8) & 0x1f;
moel@79
   376
                // factor = multiplier * 2 to handle non integer multipliers 
moel@79
   377
                uint factor = (multiplier << 1) | ((eax >> 14) & 1);
moel@79
   378
                uint maxFactor = (maxMultiplier << 1) | ((edx >> 14) & 1);
moel@79
   379
                if (maxFactor > 0) {
moel@79
   380
                  coreClocks[i].Value = (float)(factor * maxClock / maxFactor);
moel@79
   381
                  busClock = (float)(2 * maxClock / maxFactor);
moel@79
   382
                }
moel@46
   383
              }
moel@79
   384
            } else { // Intel Pentium 4
moel@79
   385
              // if IA32_PERF_STATUS is not available, assume maxClock
moel@79
   386
              coreClocks[i].Value = (float)maxClock;
moel@79
   387
            }
moel@79
   388
          }
moel@79
   389
          if (busClock > 0) {
moel@79
   390
            this.busClock.Value = (float)busClock;
moel@79
   391
            ActivateSensor(this.busClock);
moel@46
   392
          }
moel@44
   393
        }
moel@79
   394
        lastTimeStampCount = timeStampCount;
moel@79
   395
        lastTime = time;
moel@44
   396
      }
moel@46
   397
    }
moel@46
   398
  }  
moel@1
   399
}