Hardware/CPU/GenericCPU.cs
author moel.mich
Sun, 23 Sep 2012 18:37:43 +0000
changeset 380 573f1fff48b2
parent 298 96263190189a
permissions -rw-r--r--
Fixed Issue 387. The new implementation does not try to start a ring 0 driver that already exists, but could not be opened. It tries to delete the driver and install it new. The driver is now stored temporarily in the application folder. The driver is not correctly removed on system shutdown.
moel@191
     1
/*
moel@191
     2
 
moel@344
     3
  This Source Code Form is subject to the terms of the Mozilla Public
moel@344
     4
  License, v. 2.0. If a copy of the MPL was not distributed with this
moel@344
     5
  file, You can obtain one at http://mozilla.org/MPL/2.0/.
moel@191
     6
 
moel@344
     7
  Copyright (C) 2010-2011 Michael Möller <mmoeller@openhardwaremonitor.org>
moel@344
     8
	
moel@191
     9
*/
moel@191
    10
moel@191
    11
using System;
moel@191
    12
using System.Collections.Generic;
moel@191
    13
using System.Diagnostics;
moel@191
    14
using System.Globalization;
moel@236
    15
using System.Runtime.InteropServices;
moel@191
    16
using System.Text;
moel@191
    17
using System.Threading;
moel@191
    18
moel@191
    19
namespace OpenHardwareMonitor.Hardware.CPU {
moel@195
    20
  internal class GenericCPU : Hardware {
moel@191
    21
moel@191
    22
    protected readonly CPUID[][] cpuid;
moel@191
    23
   
moel@191
    24
    protected readonly uint family;
moel@191
    25
    protected readonly uint model;
moel@191
    26
    protected readonly uint stepping;
moel@191
    27
moel@191
    28
    protected readonly int processorIndex;
moel@191
    29
    protected readonly int coreCount;
moel@191
    30
moel@236
    31
    private readonly bool hasModelSpecificRegisters;
moel@236
    32
moel@201
    33
    private readonly bool hasTimeStampCounter;
moel@201
    34
    private readonly bool isInvariantTimeStampCounter;
moel@201
    35
    private readonly double estimatedTimeStampCounterFrequency;
moel@279
    36
    private readonly double estimatedTimeStampCounterFrequencyError;
moel@191
    37
moel@191
    38
    private ulong lastTimeStampCount;
moel@191
    39
    private long lastTime;
moel@279
    40
    private double timeStampCounterFrequency;
moel@279
    41
    
moel@191
    42
moel@195
    43
    private readonly Vendor vendor;
moel@191
    44
moel@191
    45
    private readonly CPULoad cpuLoad;
moel@191
    46
    private readonly Sensor totalLoad;
moel@191
    47
    private readonly Sensor[] coreLoads;
moel@191
    48
moel@191
    49
    protected string CoreString(int i) {
moel@191
    50
      if (coreCount == 1)
moel@191
    51
        return "CPU Core";
moel@191
    52
      else
moel@191
    53
        return "CPU Core #" + (i + 1);
moel@191
    54
    }
moel@191
    55
moel@275
    56
    public GenericCPU(int processorIndex, CPUID[][] cpuid, ISettings settings)
moel@275
    57
      : base(cpuid[0][0].Name, CreateIdentifier(cpuid[0][0].Vendor, 
moel@275
    58
      processorIndex), settings)
moel@275
    59
    {
moel@191
    60
      this.cpuid = cpuid;
moel@191
    61
moel@191
    62
      this.vendor = cpuid[0][0].Vendor;
moel@191
    63
moel@191
    64
      this.family = cpuid[0][0].Family;
moel@191
    65
      this.model = cpuid[0][0].Model;
moel@191
    66
      this.stepping = cpuid[0][0].Stepping;
moel@191
    67
moel@191
    68
      this.processorIndex = processorIndex;
moel@275
    69
      this.coreCount = cpuid.Length;  
moel@236
    70
  
moel@236
    71
      // check if processor has MSRs
moel@236
    72
      if (cpuid[0][0].Data.GetLength(0) > 1
moel@236
    73
        && (cpuid[0][0].Data[1, 3] & 0x20) != 0)
moel@236
    74
        hasModelSpecificRegisters = true;
moel@236
    75
      else
moel@236
    76
        hasModelSpecificRegisters = false;
moel@191
    77
moel@201
    78
      // check if processor has a TSC
moel@191
    79
      if (cpuid[0][0].Data.GetLength(0) > 1
moel@191
    80
        && (cpuid[0][0].Data[1, 3] & 0x10) != 0)
moel@201
    81
        hasTimeStampCounter = true;
moel@191
    82
      else
moel@201
    83
        hasTimeStampCounter = false;
moel@191
    84
moel@201
    85
      // check if processor supports an invariant TSC 
moel@191
    86
      if (cpuid[0][0].ExtData.GetLength(0) > 7
moel@191
    87
        && (cpuid[0][0].ExtData[7, 3] & 0x100) != 0)
moel@201
    88
        isInvariantTimeStampCounter = true;
moel@191
    89
      else
moel@201
    90
        isInvariantTimeStampCounter = false;
moel@191
    91
moel@191
    92
      if (coreCount > 1)
moel@191
    93
        totalLoad = new Sensor("CPU Total", 0, SensorType.Load, this, settings);
moel@191
    94
      else
moel@191
    95
        totalLoad = null;
moel@191
    96
      coreLoads = new Sensor[coreCount];
moel@191
    97
      for (int i = 0; i < coreLoads.Length; i++)
moel@191
    98
        coreLoads[i] = new Sensor(CoreString(i), i + 1,
moel@191
    99
          SensorType.Load, this, settings);
moel@191
   100
      cpuLoad = new CPULoad(cpuid);
moel@191
   101
      if (cpuLoad.IsAvailable) {
moel@191
   102
        foreach (Sensor sensor in coreLoads)
moel@191
   103
          ActivateSensor(sensor);
moel@191
   104
        if (totalLoad != null)
moel@191
   105
          ActivateSensor(totalLoad);
moel@191
   106
      }
moel@191
   107
moel@203
   108
      if (hasTimeStampCounter) {
moel@238
   109
        ulong mask = ThreadAffinity.Set(1UL << cpuid[0][0].Thread);
moel@279
   110
moel@279
   111
        EstimateTimeStampCounterFrequency(
moel@279
   112
          out estimatedTimeStampCounterFrequency, 
moel@279
   113
          out estimatedTimeStampCounterFrequencyError);  
moel@238
   114
        
moel@238
   115
        ThreadAffinity.Set(mask);
moel@203
   116
      } else {
moel@201
   117
        estimatedTimeStampCounterFrequency = 0;
moel@203
   118
      }
moel@203
   119
moel@203
   120
      timeStampCounterFrequency = estimatedTimeStampCounterFrequency;                  
moel@191
   121
    }
moel@191
   122
moel@275
   123
    private static Identifier CreateIdentifier(Vendor vendor,
moel@275
   124
      int processorIndex) 
moel@275
   125
    {
moel@275
   126
      string s;
moel@275
   127
      switch (vendor) {
moel@275
   128
        case Vendor.AMD: s = "amdcpu"; break;
moel@275
   129
        case Vendor.Intel: s = "intelcpu"; break;
moel@275
   130
        default: s = "genericcpu"; break;
moel@275
   131
      }
moel@275
   132
      return new Identifier(s,
moel@275
   133
        processorIndex.ToString(CultureInfo.InvariantCulture));
moel@275
   134
    }
moel@275
   135
moel@279
   136
    private void EstimateTimeStampCounterFrequency(out double frequency, 
moel@279
   137
      out double error) 
moel@279
   138
  {     
moel@279
   139
      double f, e;
moel@279
   140
      
moel@191
   141
      // preload the function
moel@279
   142
      EstimateTimeStampCounterFrequency(0, out f, out e);
moel@279
   143
      EstimateTimeStampCounterFrequency(0, out f, out e);
moel@191
   144
moel@279
   145
      // estimate the frequency
moel@279
   146
      error = double.MaxValue;
moel@279
   147
      frequency = 0;
moel@279
   148
      for (int i = 0; i < 5; i++) {
moel@279
   149
        EstimateTimeStampCounterFrequency(0.025, out f, out e);
moel@279
   150
        if (e < error) {
moel@279
   151
          error = e;
moel@279
   152
          frequency = f;
moel@279
   153
        }
moel@279
   154
moel@279
   155
        if (error < 1e-4)
moel@279
   156
          break;
moel@279
   157
      }                
moel@191
   158
    }
moel@191
   159
moel@279
   160
    private void EstimateTimeStampCounterFrequency(double timeWindow, 
moel@279
   161
      out double frequency, out double error) 
moel@279
   162
    {
moel@191
   163
      long ticks = (long)(timeWindow * Stopwatch.Frequency);
moel@236
   164
      ulong countBegin, countEnd;
moel@191
   165
moel@191
   166
      long timeBegin = Stopwatch.GetTimestamp() +
moel@191
   167
        (long)Math.Ceiling(0.001 * ticks);
moel@191
   168
      long timeEnd = timeBegin + ticks;
moel@279
   169
moel@191
   170
      while (Stopwatch.GetTimestamp() < timeBegin) { }
moel@236
   171
      countBegin = Opcode.Rdtsc();
moel@279
   172
      long afterBegin = Stopwatch.GetTimestamp();
moel@279
   173
moel@191
   174
      while (Stopwatch.GetTimestamp() < timeEnd) { }
moel@236
   175
      countEnd = Opcode.Rdtsc();
moel@279
   176
      long afterEnd = Stopwatch.GetTimestamp();
moel@191
   177
moel@279
   178
      double delta = (timeEnd - timeBegin);
moel@279
   179
      frequency = 1e-6 * 
moel@279
   180
        (((double)(countEnd - countBegin)) * Stopwatch.Frequency) / delta;
moel@279
   181
moel@279
   182
      double beginError = (afterBegin - timeBegin) / delta;
moel@279
   183
      double endError = (afterEnd - timeEnd) / delta;
moel@279
   184
      error = beginError + endError;
moel@191
   185
    }
moel@191
   186
moel@236
   187
moel@191
   188
    private static void AppendMSRData(StringBuilder r, uint msr, int thread) {
moel@191
   189
      uint eax, edx;
moel@238
   190
      if (Ring0.RdmsrTx(msr, out eax, out edx, 1UL << thread)) {
moel@191
   191
        r.Append(" ");
moel@191
   192
        r.Append((msr).ToString("X8", CultureInfo.InvariantCulture));
moel@191
   193
        r.Append("  ");
moel@191
   194
        r.Append((edx).ToString("X8", CultureInfo.InvariantCulture));
moel@191
   195
        r.Append("  ");
moel@191
   196
        r.Append((eax).ToString("X8", CultureInfo.InvariantCulture));
moel@191
   197
        r.AppendLine();
moel@191
   198
      }
moel@191
   199
    }
moel@191
   200
moel@191
   201
    protected virtual uint[] GetMSRs() {
moel@191
   202
      return null;
moel@191
   203
    }
moel@191
   204
moel@191
   205
    public override string GetReport() {
moel@191
   206
      StringBuilder r = new StringBuilder();
moel@191
   207
moel@191
   208
      switch (vendor) {
moel@195
   209
        case Vendor.AMD: r.AppendLine("AMD CPU"); break;
moel@191
   210
        case Vendor.Intel: r.AppendLine("Intel CPU"); break;
moel@191
   211
        default: r.AppendLine("Generic CPU"); break;
moel@191
   212
      }
moel@191
   213
moel@191
   214
      r.AppendLine();
moel@191
   215
      r.AppendFormat("Name: {0}{1}", name, Environment.NewLine);
moel@191
   216
      r.AppendFormat("Number of Cores: {0}{1}", coreCount,
moel@191
   217
        Environment.NewLine);
moel@191
   218
      r.AppendFormat("Threads per Core: {0}{1}", cpuid[0].Length,
moel@191
   219
        Environment.NewLine);
moel@191
   220
      r.AppendLine(string.Format(CultureInfo.InvariantCulture,
moel@191
   221
        "Timer Frequency: {0} MHz", Stopwatch.Frequency * 1e-6));
moel@201
   222
      r.AppendLine("Time Stamp Counter: " + (hasTimeStampCounter ? (
moel@201
   223
        isInvariantTimeStampCounter ? "Invariant" : "Not Invariant") : "None"));
moel@191
   224
      r.AppendLine(string.Format(CultureInfo.InvariantCulture,
moel@279
   225
        "Estimated Time Stamp Counter Frequency: {0} MHz",
moel@279
   226
        Math.Round(estimatedTimeStampCounterFrequency * 100) * 0.01));
moel@279
   227
      r.AppendLine(string.Format(CultureInfo.InvariantCulture,
moel@279
   228
        "Estimated Time Stamp Counter Frequency Error: {0} Mhz",
moel@279
   229
        Math.Round(estimatedTimeStampCounterFrequency *
moel@279
   230
        estimatedTimeStampCounterFrequencyError * 1e5) * 1e-5));
moel@279
   231
      r.AppendLine(string.Format(CultureInfo.InvariantCulture,
moel@201
   232
        "Time Stamp Counter Frequency: {0} MHz",
moel@201
   233
        Math.Round(timeStampCounterFrequency * 100) * 0.01));   
moel@191
   234
      r.AppendLine();
moel@191
   235
moel@191
   236
      uint[] msrArray = GetMSRs();
moel@191
   237
      if (msrArray != null && msrArray.Length > 0) {
moel@191
   238
        for (int i = 0; i < cpuid.Length; i++) {
moel@191
   239
          r.AppendLine("MSR Core #" + (i + 1));
moel@191
   240
          r.AppendLine();
moel@191
   241
          r.AppendLine(" MSR       EDX       EAX");
moel@191
   242
          foreach (uint msr in msrArray)
moel@191
   243
            AppendMSRData(r, msr, cpuid[i][0].Thread);
moel@191
   244
          r.AppendLine();
moel@191
   245
        }
moel@191
   246
      }
moel@191
   247
moel@191
   248
      return r.ToString();
moel@191
   249
    }
moel@191
   250
moel@191
   251
    public override HardwareType HardwareType {
moel@191
   252
      get { return HardwareType.CPU; }
moel@191
   253
    }
moel@191
   254
moel@236
   255
    public bool HasModelSpecificRegisters {
moel@236
   256
      get { return hasModelSpecificRegisters; }
moel@236
   257
    }
moel@236
   258
moel@201
   259
    public bool HasTimeStampCounter {
moel@201
   260
      get { return hasTimeStampCounter; }
moel@201
   261
    }
moel@201
   262
moel@201
   263
    public double TimeStampCounterFrequency {
moel@201
   264
      get { return timeStampCounterFrequency; }
moel@191
   265
    }
moel@191
   266
moel@191
   267
    public override void Update() {
moel@222
   268
      if (hasTimeStampCounter && isInvariantTimeStampCounter) {
moel@236
   269
moel@236
   270
        // make sure always the same thread is used
moel@238
   271
        ulong mask = ThreadAffinity.Set(1UL << cpuid[0][0].Thread);
moel@222
   272
moel@222
   273
        // read time before and after getting the TSC to estimate the error
moel@222
   274
        long firstTime = Stopwatch.GetTimestamp();
moel@236
   275
        ulong timeStampCount = Opcode.Rdtsc();
moel@191
   276
        long time = Stopwatch.GetTimestamp();
moel@222
   277
moel@236
   278
        // restore the thread affinity mask
moel@238
   279
        ThreadAffinity.Set(mask);
moel@236
   280
moel@191
   281
        double delta = ((double)(time - lastTime)) / Stopwatch.Frequency;
moel@222
   282
        double error = ((double)(time - firstTime)) / Stopwatch.Frequency;
moel@222
   283
moel@222
   284
        // only use data if they are measured accuarte enough (max 0.1ms delay)
moel@222
   285
        if (error < 0.0001) {
moel@222
   286
moel@222
   287
          // ignore the first reading because there are no initial values 
moel@222
   288
          // ignore readings with too large or too small time window
moel@222
   289
          if (lastTime != 0 && delta > 0.5 && delta < 2) {
moel@222
   290
moel@222
   291
            // update the TSC frequency with the new value
moel@222
   292
            timeStampCounterFrequency =
moel@201
   293
              (timeStampCount - lastTimeStampCount) / (1e6 * delta);
moel@222
   294
          }
moel@191
   295
moel@191
   296
          lastTimeStampCount = timeStampCount;
moel@191
   297
          lastTime = time;
moel@191
   298
        }        
moel@191
   299
      }
moel@191
   300
moel@191
   301
      if (cpuLoad.IsAvailable) {
moel@191
   302
        cpuLoad.Update();
moel@191
   303
        for (int i = 0; i < coreLoads.Length; i++)
moel@191
   304
          coreLoads[i].Value = cpuLoad.GetCoreLoad(i);
moel@191
   305
        if (totalLoad != null)
moel@191
   306
          totalLoad.Value = cpuLoad.GetTotalLoad();
moel@191
   307
      }
moel@191
   308
    }
moel@191
   309
  }
moel@191
   310
}