Hardware/CPU/CPUID.cs
author moel.mich
Tue, 25 May 2010 18:57:28 +0000
changeset 127 76aaf45a01c7
parent 112 69d29f1a2307
child 165 813d8bc3192f
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@90
     1
/*
moel@90
     2
  
moel@90
     3
  Version: MPL 1.1/GPL 2.0/LGPL 2.1
moel@90
     4
moel@90
     5
  The contents of this file are subject to the Mozilla Public License Version
moel@90
     6
  1.1 (the "License"); you may not use this file except in compliance with
moel@90
     7
  the License. You may obtain a copy of the License at
moel@90
     8
 
moel@90
     9
  http://www.mozilla.org/MPL/
moel@90
    10
moel@90
    11
  Software distributed under the License is distributed on an "AS IS" basis,
moel@90
    12
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
moel@90
    13
  for the specific language governing rights and limitations under the License.
moel@90
    14
moel@90
    15
  The Original Code is the Open Hardware Monitor code.
moel@90
    16
moel@90
    17
  The Initial Developer of the Original Code is 
moel@90
    18
  Michael Möller <m.moeller@gmx.ch>.
moel@90
    19
  Portions created by the Initial Developer are Copyright (C) 2009-2010
moel@90
    20
  the Initial Developer. All Rights Reserved.
moel@90
    21
moel@90
    22
  Contributor(s):
moel@90
    23
moel@90
    24
  Alternatively, the contents of this file may be used under the terms of
moel@90
    25
  either the GNU General Public License Version 2 or later (the "GPL"), or
moel@90
    26
  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
moel@90
    27
  in which case the provisions of the GPL or the LGPL are applicable instead
moel@90
    28
  of those above. If you wish to allow use of your version of this file only
moel@90
    29
  under the terms of either the GPL or the LGPL, and not to allow others to
moel@90
    30
  use your version of this file under the terms of the MPL, indicate your
moel@90
    31
  decision by deleting the provisions above and replace them with the notice
moel@90
    32
  and other provisions required by the GPL or the LGPL. If you do not delete
moel@90
    33
  the provisions above, a recipient may use your version of this file under
moel@90
    34
  the terms of any one of the MPL, the GPL or the LGPL.
moel@90
    35
 
moel@90
    36
*/
moel@90
    37
moel@90
    38
using System;
moel@90
    39
using System.Collections.Generic;
moel@90
    40
using System.Text;
moel@90
    41
moel@90
    42
namespace OpenHardwareMonitor.Hardware.CPU {
moel@90
    43
  
moel@90
    44
  public enum Vendor {
moel@90
    45
    Unknown,
moel@90
    46
    Intel,
moel@90
    47
    AMD,
moel@90
    48
  }
moel@90
    49
  
moel@90
    50
  public class CPUID {
moel@90
    51
moel@90
    52
    private int thread;
moel@90
    53
moel@124
    54
    private Vendor vendor = Vendor.Unknown;
moel@90
    55
moel@124
    56
    private string cpuBrandString = "";
moel@124
    57
    private string name = "";
moel@90
    58
moel@124
    59
    private uint[,] cpuidData = new uint[0, 0];
moel@124
    60
    private uint[,] cpuidExtData = new uint[0, 0];
moel@90
    61
moel@90
    62
    private uint family;
moel@90
    63
    private uint model;
moel@90
    64
    private uint stepping;
moel@90
    65
moel@90
    66
    private uint apicId;
moel@90
    67
moel@90
    68
    private uint threadMaskWith;
moel@90
    69
    private uint coreMaskWith;
moel@90
    70
moel@90
    71
    private uint processorId;
moel@90
    72
    private uint coreId;
moel@90
    73
    private uint threadId;
moel@90
    74
moel@90
    75
    public static uint CPUID_0 = 0;
moel@90
    76
    public static uint CPUID_EXT = 0x80000000;
moel@90
    77
moel@90
    78
    private void AppendRegister(StringBuilder b, uint value) {
moel@90
    79
      b.Append((char)((value) & 0xff));
moel@90
    80
      b.Append((char)((value >> 8) & 0xff));
moel@90
    81
      b.Append((char)((value >> 16) & 0xff));
moel@90
    82
      b.Append((char)((value >> 24) & 0xff));
moel@90
    83
    }
moel@90
    84
moel@105
    85
    private uint NextLog2(long x) {
moel@105
    86
      if (x <= 0)
moel@105
    87
        return 0;
moel@105
    88
moel@105
    89
      x--;
moel@105
    90
      uint count = 0;
moel@105
    91
      while (x > 0) {
moel@105
    92
        x >>= 1;
moel@105
    93
        count++;
moel@105
    94
      }
moel@105
    95
moel@105
    96
      return count;
moel@105
    97
    }
moel@105
    98
moel@90
    99
    public CPUID(int thread) {
moel@90
   100
      this.thread = thread;
moel@90
   101
moel@124
   102
      uint maxCpuid = 0;
moel@124
   103
      uint maxCpuidExt = 0;
moel@124
   104
moel@90
   105
      uint eax, ebx, ecx, edx;
moel@90
   106
moel@112
   107
      if (thread >= 32)
moel@112
   108
        throw new ArgumentException();
moel@90
   109
      UIntPtr mask = (UIntPtr)(1L << thread);
moel@90
   110
moel@90
   111
      if (WinRing0.CpuidTx(CPUID_0, 0,
moel@90
   112
          out eax, out ebx, out ecx, out edx, mask)) {
moel@112
   113
        if (eax > 0)
moel@112
   114
          maxCpuid = eax;
moel@112
   115
        else
moel@112
   116
          return;
moel@112
   117
moel@90
   118
        StringBuilder vendorBuilder = new StringBuilder();
moel@90
   119
        AppendRegister(vendorBuilder, ebx);
moel@90
   120
        AppendRegister(vendorBuilder, edx);
moel@90
   121
        AppendRegister(vendorBuilder, ecx);
moel@90
   122
        string cpuVendor = vendorBuilder.ToString();
moel@90
   123
        switch (cpuVendor) {
moel@90
   124
          case "GenuineIntel":
moel@90
   125
            vendor = Vendor.Intel;
moel@90
   126
            break;
moel@90
   127
          case "AuthenticAMD":
moel@90
   128
            vendor = Vendor.AMD;
moel@90
   129
            break;
moel@90
   130
          default:
moel@90
   131
            vendor = Vendor.Unknown;
moel@90
   132
            break;
moel@90
   133
        }
moel@90
   134
        eax = ebx = ecx = edx = 0;
moel@90
   135
        if (WinRing0.CpuidTx(CPUID_EXT, 0,
moel@112
   136
          out eax, out ebx, out ecx, out edx, mask)) {
moel@112
   137
          if (eax > CPUID_EXT)
moel@112
   138
            maxCpuidExt = eax - CPUID_EXT;
moel@112
   139
          else
moel@112
   140
            return;
moel@124
   141
        } else {
moel@124
   142
          throw new ArgumentException();
moel@112
   143
        }
moel@90
   144
      } else {
moel@90
   145
        throw new ArgumentException();
moel@90
   146
      }
moel@90
   147
moel@112
   148
      maxCpuid = Math.Min(maxCpuid, 1024);
moel@112
   149
      maxCpuidExt = Math.Min(maxCpuidExt, 1024);   
moel@90
   150
moel@90
   151
      cpuidData = new uint[maxCpuid + 1, 4];
moel@90
   152
      for (uint i = 0; i < (maxCpuid + 1); i++)
moel@90
   153
        WinRing0.CpuidTx(CPUID_0 + i, 0, 
moel@90
   154
          out cpuidData[i, 0], out cpuidData[i, 1],
moel@90
   155
          out cpuidData[i, 2], out cpuidData[i, 3], mask);
moel@90
   156
moel@95
   157
      cpuidExtData = new uint[maxCpuidExt + 1, 4];
moel@95
   158
      for (uint i = 0; i < (maxCpuidExt + 1); i++)
moel@90
   159
        WinRing0.CpuidTx(CPUID_EXT + i, 0, 
moel@90
   160
          out cpuidExtData[i, 0], out cpuidExtData[i, 1], 
moel@90
   161
          out cpuidExtData[i, 2], out cpuidExtData[i, 3], mask);
moel@90
   162
moel@90
   163
      StringBuilder nameBuilder = new StringBuilder();
moel@90
   164
      for (uint i = 2; i <= 4; i++) {
moel@90
   165
        if (WinRing0.CpuidTx(CPUID_EXT + i, 0, 
moel@90
   166
          out eax, out ebx, out ecx, out edx, mask)) 
moel@90
   167
        {
moel@90
   168
          AppendRegister(nameBuilder, eax);
moel@90
   169
          AppendRegister(nameBuilder, ebx);
moel@90
   170
          AppendRegister(nameBuilder, ecx);
moel@90
   171
          AppendRegister(nameBuilder, edx);
moel@90
   172
        }
moel@90
   173
      }
moel@90
   174
      nameBuilder.Replace('\0', ' ');
moel@90
   175
      cpuBrandString = nameBuilder.ToString().Trim();
moel@90
   176
      nameBuilder.Replace("(R)", " ");
moel@90
   177
      nameBuilder.Replace("(TM)", " ");
moel@90
   178
      nameBuilder.Replace("(tm)", " ");
moel@90
   179
      nameBuilder.Replace("CPU", "");
moel@90
   180
      for (int i = 0; i < 10; i++) nameBuilder.Replace("  ", " ");
moel@90
   181
      name = nameBuilder.ToString();
moel@90
   182
      if (name.Contains("@"))
moel@90
   183
        name = name.Remove(name.LastIndexOf('@'));
moel@95
   184
      name = name.Trim();      
moel@90
   185
moel@90
   186
      this.family = ((cpuidData[1, 0] & 0x0FF00000) >> 20) +
moel@90
   187
        ((cpuidData[1, 0] & 0x0F00) >> 8);
moel@90
   188
      this.model = ((cpuidData[1, 0] & 0x0F0000) >> 12) +
moel@90
   189
        ((cpuidData[1, 0] & 0xF0) >> 4);
moel@90
   190
      this.stepping = (cpuidData[1, 0] & 0x0F);
moel@90
   191
moel@90
   192
      this.apicId = (cpuidData[1, 1] >> 24) & 0xFF;
moel@90
   193
moel@90
   194
      switch (vendor) {
moel@90
   195
        case Vendor.Intel:
moel@90
   196
          uint maxCoreAndThreadIdPerPackage = (cpuidData[1, 1] >> 16) & 0xFF;
moel@95
   197
          uint maxCoreIdPerPackage;
moel@95
   198
          if (maxCpuid >= 4)
moel@95
   199
            maxCoreIdPerPackage = ((cpuidData[4, 0] >> 26) & 0x3F) + 1;
moel@95
   200
          else
moel@95
   201
            maxCoreIdPerPackage = 1;
moel@105
   202
          threadMaskWith = 
moel@105
   203
            NextLog2(maxCoreAndThreadIdPerPackage / maxCoreIdPerPackage);
moel@105
   204
          coreMaskWith = NextLog2(maxCoreIdPerPackage);
moel@90
   205
          break;
moel@90
   206
        case Vendor.AMD:
moel@95
   207
          uint corePerPackage;
moel@95
   208
          if (maxCpuidExt >= 8)
moel@95
   209
            corePerPackage = (cpuidExtData[8, 2] & 0xFF) + 1;
moel@95
   210
          else
moel@95
   211
            corePerPackage = 1;
moel@90
   212
          threadMaskWith = 0;
moel@105
   213
          coreMaskWith = NextLog2(corePerPackage);
moel@90
   214
          break;
moel@90
   215
        default:
moel@90
   216
          threadMaskWith = 0;
moel@90
   217
          coreMaskWith = 0;
moel@90
   218
          break;
moel@90
   219
      }
moel@90
   220
moel@90
   221
      processorId = (uint)(apicId >> (int)(coreMaskWith + threadMaskWith));
moel@95
   222
      coreId = (uint)((apicId >> (int)(threadMaskWith)) 
moel@102
   223
        - (processorId << (int)(coreMaskWith)));
moel@95
   224
      threadId = apicId
moel@95
   225
        - (processorId << (int)(coreMaskWith + threadMaskWith))
moel@95
   226
        - (coreId << (int)(threadMaskWith)); 
moel@90
   227
    }
moel@90
   228
moel@90
   229
    public string Name {
moel@90
   230
      get { return name; }
moel@90
   231
    }
moel@90
   232
moel@90
   233
    public string BrandString {
moel@90
   234
      get { return cpuBrandString; }
moel@90
   235
    }
moel@90
   236
moel@90
   237
    public int Thread {
moel@90
   238
      get { return thread; }
moel@90
   239
    }
moel@90
   240
moel@90
   241
    public Vendor Vendor {
moel@90
   242
      get { return vendor; }
moel@90
   243
    }
moel@90
   244
moel@90
   245
    public uint Family {
moel@90
   246
      get { return family; }
moel@90
   247
    }
moel@90
   248
moel@90
   249
    public uint Model {
moel@90
   250
      get { return model; }
moel@90
   251
    }
moel@90
   252
moel@90
   253
    public uint Stepping {
moel@90
   254
      get { return stepping; }
moel@90
   255
    }
moel@90
   256
moel@90
   257
    public uint ApicId {
moel@90
   258
      get { return apicId; }
moel@90
   259
    }
moel@90
   260
moel@90
   261
    public uint ProcessorId {
moel@90
   262
      get { return processorId; }
moel@90
   263
    }
moel@90
   264
moel@90
   265
    public uint CoreId {
moel@90
   266
      get { return coreId; }
moel@90
   267
    }
moel@90
   268
moel@90
   269
    public uint ThreadId {
moel@90
   270
      get { return threadId; }
moel@90
   271
    }
moel@90
   272
moel@90
   273
    public uint[,] Data {
moel@90
   274
      get { return cpuidData; }
moel@90
   275
    }
moel@90
   276
moel@90
   277
    public uint[,] ExtData {
moel@90
   278
      get { return cpuidExtData; }
moel@90
   279
    }
moel@90
   280
  }
moel@90
   281
}