Hardware/CPU/GenericCPU.cs
author moel.mich
Sat, 02 Oct 2010 18:15:46 +0000
changeset 206 1fa8eddc24a7
parent 201 958e9fe8afdf
child 222 ba64bb91ebe4
permissions -rw-r--r--
Replaced HttpUtility.UrlEncode with Uri.EscapeDataString and deleted the reference to the System.Web assembly. The System.Web assembly seems to be missing on some .NET 4.0 installations (and the overhead of using it is a bit large, just for the UrlEncode method).
moel@191
     1
/*
moel@191
     2
  
moel@191
     3
  Version: MPL 1.1/GPL 2.0/LGPL 2.1
moel@191
     4
moel@191
     5
  The contents of this file are subject to the Mozilla Public License Version
moel@191
     6
  1.1 (the "License"); you may not use this file except in compliance with
moel@191
     7
  the License. You may obtain a copy of the License at
moel@191
     8
 
moel@191
     9
  http://www.mozilla.org/MPL/
moel@191
    10
moel@191
    11
  Software distributed under the License is distributed on an "AS IS" basis,
moel@191
    12
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
moel@191
    13
  for the specific language governing rights and limitations under the License.
moel@191
    14
moel@191
    15
  The Original Code is the Open Hardware Monitor code.
moel@191
    16
moel@191
    17
  The Initial Developer of the Original Code is 
moel@191
    18
  Michael Möller <m.moeller@gmx.ch>.
moel@191
    19
  Portions created by the Initial Developer are Copyright (C) 2010
moel@191
    20
  the Initial Developer. All Rights Reserved.
moel@191
    21
moel@191
    22
  Contributor(s):
moel@191
    23
moel@191
    24
  Alternatively, the contents of this file may be used under the terms of
moel@191
    25
  either the GNU General Public License Version 2 or later (the "GPL"), or
moel@191
    26
  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
moel@191
    27
  in which case the provisions of the GPL or the LGPL are applicable instead
moel@191
    28
  of those above. If you wish to allow use of your version of this file only
moel@191
    29
  under the terms of either the GPL or the LGPL, and not to allow others to
moel@191
    30
  use your version of this file under the terms of the MPL, indicate your
moel@191
    31
  decision by deleting the provisions above and replace them with the notice
moel@191
    32
  and other provisions required by the GPL or the LGPL. If you do not delete
moel@191
    33
  the provisions above, a recipient may use your version of this file under
moel@191
    34
  the terms of any one of the MPL, the GPL or the LGPL.
moel@191
    35
 
moel@191
    36
*/
moel@191
    37
moel@191
    38
using System;
moel@191
    39
using System.Collections.Generic;
moel@191
    40
using System.Diagnostics;
moel@191
    41
using System.Globalization;
moel@191
    42
using System.Text;
moel@191
    43
using System.Threading;
moel@191
    44
moel@191
    45
namespace OpenHardwareMonitor.Hardware.CPU {
moel@195
    46
  internal class GenericCPU : Hardware {
moel@191
    47
moel@191
    48
    protected readonly CPUID[][] cpuid;
moel@191
    49
   
moel@191
    50
    protected readonly uint family;
moel@191
    51
    protected readonly uint model;
moel@191
    52
    protected readonly uint stepping;
moel@191
    53
moel@191
    54
    protected readonly int processorIndex;
moel@191
    55
    protected readonly int coreCount;
moel@191
    56
    protected readonly string name;
moel@191
    57
moel@201
    58
    private readonly bool hasTimeStampCounter;
moel@201
    59
    private readonly bool isInvariantTimeStampCounter;
moel@201
    60
    private readonly double estimatedTimeStampCounterFrequency;
moel@191
    61
moel@191
    62
    private ulong lastTimeStampCount;
moel@191
    63
    private long lastTime;
moel@201
    64
    private double timeStampCounterFrequency;    
moel@191
    65
moel@195
    66
    private readonly Vendor vendor;
moel@191
    67
moel@191
    68
    private readonly CPULoad cpuLoad;
moel@191
    69
    private readonly Sensor totalLoad;
moel@191
    70
    private readonly Sensor[] coreLoads;
moel@191
    71
moel@191
    72
    protected string CoreString(int i) {
moel@191
    73
      if (coreCount == 1)
moel@191
    74
        return "CPU Core";
moel@191
    75
      else
moel@191
    76
        return "CPU Core #" + (i + 1);
moel@191
    77
    }
moel@191
    78
moel@191
    79
    public GenericCPU(int processorIndex, CPUID[][] cpuid, ISettings settings) {
moel@191
    80
      this.cpuid = cpuid;
moel@191
    81
moel@191
    82
      this.vendor = cpuid[0][0].Vendor;
moel@191
    83
moel@191
    84
      this.family = cpuid[0][0].Family;
moel@191
    85
      this.model = cpuid[0][0].Model;
moel@191
    86
      this.stepping = cpuid[0][0].Stepping;
moel@191
    87
moel@191
    88
      this.processorIndex = processorIndex;
moel@191
    89
      this.coreCount = cpuid.Length;
moel@191
    90
      this.name = cpuid[0][0].Name;      
moel@191
    91
moel@201
    92
      // check if processor has a TSC
moel@191
    93
      if (cpuid[0][0].Data.GetLength(0) > 1
moel@191
    94
        && (cpuid[0][0].Data[1, 3] & 0x10) != 0)
moel@201
    95
        hasTimeStampCounter = true;
moel@191
    96
      else
moel@201
    97
        hasTimeStampCounter = false;
moel@191
    98
moel@201
    99
      // check if processor supports an invariant TSC 
moel@191
   100
      if (cpuid[0][0].ExtData.GetLength(0) > 7
moel@191
   101
        && (cpuid[0][0].ExtData[7, 3] & 0x100) != 0)
moel@201
   102
        isInvariantTimeStampCounter = true;
moel@191
   103
      else
moel@201
   104
        isInvariantTimeStampCounter = false;
moel@191
   105
moel@191
   106
      if (coreCount > 1)
moel@191
   107
        totalLoad = new Sensor("CPU Total", 0, SensorType.Load, this, settings);
moel@191
   108
      else
moel@191
   109
        totalLoad = null;
moel@191
   110
      coreLoads = new Sensor[coreCount];
moel@191
   111
      for (int i = 0; i < coreLoads.Length; i++)
moel@191
   112
        coreLoads[i] = new Sensor(CoreString(i), i + 1,
moel@191
   113
          SensorType.Load, this, settings);
moel@191
   114
      cpuLoad = new CPULoad(cpuid);
moel@191
   115
      if (cpuLoad.IsAvailable) {
moel@191
   116
        foreach (Sensor sensor in coreLoads)
moel@191
   117
          ActivateSensor(sensor);
moel@191
   118
        if (totalLoad != null)
moel@191
   119
          ActivateSensor(totalLoad);
moel@191
   120
      }
moel@191
   121
moel@203
   122
      if (hasTimeStampCounter) {
moel@203
   123
        estimatedTimeStampCounterFrequency = 
moel@203
   124
          EstimateTimeStampCounterFrequency();
moel@203
   125
        
moel@203
   126
        // set initial values 
moel@203
   127
        uint lsb, msb;
moel@203
   128
        WinRing0.RdtscTx(out lsb, out msb, (UIntPtr)1);
moel@203
   129
        lastTime = Stopwatch.GetTimestamp();
moel@203
   130
        lastTimeStampCount = ((ulong)msb << 32) | lsb;
moel@203
   131
moel@203
   132
      } else {
moel@201
   133
        estimatedTimeStampCounterFrequency = 0;
moel@191
   134
moel@203
   135
        lastTime = 0;
moel@203
   136
        lastTimeStampCount = 0;
moel@203
   137
      }
moel@203
   138
moel@203
   139
      timeStampCounterFrequency = estimatedTimeStampCounterFrequency;                  
moel@191
   140
    }
moel@191
   141
moel@201
   142
    private static double EstimateTimeStampCounterFrequency() {
moel@191
   143
      // preload the function
moel@201
   144
      EstimateTimeStampCounterFrequency(0);
moel@201
   145
      EstimateTimeStampCounterFrequency(0);
moel@191
   146
moel@201
   147
      // estimate the frequency in MHz      
moel@201
   148
      List<double> estimatedFrequency = new List<double>(3);
moel@191
   149
      for (int i = 0; i < 3; i++)
moel@201
   150
        estimatedFrequency.Add(1e-6 * EstimateTimeStampCounterFrequency(0.025));
moel@201
   151
      estimatedFrequency.Sort();
moel@201
   152
      return estimatedFrequency[1];
moel@191
   153
    }
moel@191
   154
moel@201
   155
    private static double EstimateTimeStampCounterFrequency(double timeWindow) {
moel@191
   156
      long ticks = (long)(timeWindow * Stopwatch.Frequency);
moel@191
   157
      uint lsbBegin, msbBegin, lsbEnd, msbEnd;
moel@191
   158
moel@191
   159
      Thread.BeginThreadAffinity();
moel@191
   160
      long timeBegin = Stopwatch.GetTimestamp() +
moel@191
   161
        (long)Math.Ceiling(0.001 * ticks);
moel@191
   162
      long timeEnd = timeBegin + ticks;
moel@191
   163
      while (Stopwatch.GetTimestamp() < timeBegin) { }
moel@191
   164
      WinRing0.Rdtsc(out lsbBegin, out msbBegin);
moel@191
   165
      while (Stopwatch.GetTimestamp() < timeEnd) { }
moel@191
   166
      WinRing0.Rdtsc(out lsbEnd, out msbEnd);
moel@191
   167
      Thread.EndThreadAffinity();
moel@191
   168
moel@191
   169
      ulong countBegin = ((ulong)msbBegin << 32) | lsbBegin;
moel@191
   170
      ulong countEnd = ((ulong)msbEnd << 32) | lsbEnd;
moel@191
   171
moel@191
   172
      return (((double)(countEnd - countBegin)) * Stopwatch.Frequency) /
moel@191
   173
        (timeEnd - timeBegin);
moel@191
   174
    }
moel@191
   175
moel@191
   176
    private static void AppendMSRData(StringBuilder r, uint msr, int thread) {
moel@191
   177
      uint eax, edx;
moel@191
   178
      if (WinRing0.RdmsrTx(msr, out eax, out edx, (UIntPtr)(1L << thread))) {
moel@191
   179
        r.Append(" ");
moel@191
   180
        r.Append((msr).ToString("X8", CultureInfo.InvariantCulture));
moel@191
   181
        r.Append("  ");
moel@191
   182
        r.Append((edx).ToString("X8", CultureInfo.InvariantCulture));
moel@191
   183
        r.Append("  ");
moel@191
   184
        r.Append((eax).ToString("X8", CultureInfo.InvariantCulture));
moel@191
   185
        r.AppendLine();
moel@191
   186
      }
moel@191
   187
    }
moel@191
   188
moel@191
   189
    protected virtual uint[] GetMSRs() {
moel@191
   190
      return null;
moel@191
   191
    }
moel@191
   192
moel@191
   193
    public override string GetReport() {
moel@191
   194
      StringBuilder r = new StringBuilder();
moel@191
   195
moel@191
   196
      switch (vendor) {
moel@195
   197
        case Vendor.AMD: r.AppendLine("AMD CPU"); break;
moel@191
   198
        case Vendor.Intel: r.AppendLine("Intel CPU"); break;
moel@191
   199
        default: r.AppendLine("Generic CPU"); break;
moel@191
   200
      }
moel@191
   201
moel@191
   202
      r.AppendLine();
moel@191
   203
      r.AppendFormat("Name: {0}{1}", name, Environment.NewLine);
moel@191
   204
      r.AppendFormat("Number of Cores: {0}{1}", coreCount,
moel@191
   205
        Environment.NewLine);
moel@191
   206
      r.AppendFormat("Threads per Core: {0}{1}", cpuid[0].Length,
moel@191
   207
        Environment.NewLine);
moel@191
   208
      r.AppendLine(string.Format(CultureInfo.InvariantCulture,
moel@191
   209
        "Timer Frequency: {0} MHz", Stopwatch.Frequency * 1e-6));
moel@201
   210
      r.AppendLine("Time Stamp Counter: " + (hasTimeStampCounter ? (
moel@201
   211
        isInvariantTimeStampCounter ? "Invariant" : "Not Invariant") : "None"));
moel@191
   212
      r.AppendLine(string.Format(CultureInfo.InvariantCulture,
moel@201
   213
        "Time Stamp Counter Frequency: {0} MHz",
moel@201
   214
        Math.Round(timeStampCounterFrequency * 100) * 0.01));   
moel@191
   215
      r.AppendLine();
moel@191
   216
moel@191
   217
      uint[] msrArray = GetMSRs();
moel@191
   218
      if (msrArray != null && msrArray.Length > 0) {
moel@191
   219
        for (int i = 0; i < cpuid.Length; i++) {
moel@191
   220
          r.AppendLine("MSR Core #" + (i + 1));
moel@191
   221
          r.AppendLine();
moel@191
   222
          r.AppendLine(" MSR       EDX       EAX");
moel@191
   223
          foreach (uint msr in msrArray)
moel@191
   224
            AppendMSRData(r, msr, cpuid[i][0].Thread);
moel@191
   225
          r.AppendLine();
moel@191
   226
        }
moel@191
   227
      }
moel@191
   228
moel@191
   229
      return r.ToString();
moel@191
   230
    }
moel@191
   231
moel@191
   232
    public override Identifier Identifier {
moel@191
   233
      get {
moel@191
   234
        string s;
moel@191
   235
        switch (vendor) {
moel@191
   236
          case Vendor.AMD: s = "amdcpu"; break;
moel@191
   237
          case Vendor.Intel: s = "intelcpu"; break;
moel@191
   238
          default: s = "genericcpu"; break;
moel@191
   239
        }
moel@191
   240
        return new Identifier(s, 
moel@191
   241
          processorIndex.ToString(CultureInfo.InvariantCulture));
moel@191
   242
      }
moel@191
   243
    }
moel@191
   244
moel@191
   245
    public override string Name {
moel@191
   246
      get { return name; }
moel@191
   247
    }
moel@191
   248
moel@191
   249
    public override HardwareType HardwareType {
moel@191
   250
      get { return HardwareType.CPU; }
moel@191
   251
    }
moel@191
   252
moel@201
   253
    public bool HasTimeStampCounter {
moel@201
   254
      get { return hasTimeStampCounter; }
moel@201
   255
    }
moel@201
   256
moel@201
   257
    public double TimeStampCounterFrequency {
moel@201
   258
      get { return timeStampCounterFrequency; }
moel@191
   259
    }
moel@191
   260
moel@191
   261
    public override void Update() {
moel@201
   262
      if (hasTimeStampCounter) {
moel@191
   263
        uint lsb, msb;
moel@191
   264
        WinRing0.RdtscTx(out lsb, out msb, (UIntPtr)1);
moel@191
   265
        long time = Stopwatch.GetTimestamp();
moel@191
   266
        ulong timeStampCount = ((ulong)msb << 32) | lsb;
moel@191
   267
        double delta = ((double)(time - lastTime)) / Stopwatch.Frequency;
moel@191
   268
        if (delta > 0.5) {
moel@201
   269
          if (isInvariantTimeStampCounter)
moel@201
   270
            timeStampCounterFrequency = 
moel@201
   271
              (timeStampCount - lastTimeStampCount) / (1e6 * delta);
moel@191
   272
          else
moel@201
   273
            timeStampCounterFrequency = estimatedTimeStampCounterFrequency;
moel@191
   274
moel@191
   275
          lastTimeStampCount = timeStampCount;
moel@191
   276
          lastTime = time;
moel@191
   277
        }        
moel@191
   278
      }
moel@191
   279
moel@191
   280
      if (cpuLoad.IsAvailable) {
moel@191
   281
        cpuLoad.Update();
moel@191
   282
        for (int i = 0; i < coreLoads.Length; i++)
moel@191
   283
          coreLoads[i].Value = cpuLoad.GetCoreLoad(i);
moel@191
   284
        if (totalLoad != null)
moel@191
   285
          totalLoad.Value = cpuLoad.GetTotalLoad();
moel@191
   286
      }
moel@191
   287
    }
moel@191
   288
  }
moel@191
   289
}