Hardware/CPU/GenericCPU.cs
author moel.mich
Thu, 11 Nov 2010 21:22:24 +0000
changeset 241 52007c404f32
parent 236 763675f19ff4
child 266 2687ac753d90
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@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@236
    42
using System.Runtime.InteropServices;
moel@191
    43
using System.Text;
moel@191
    44
using System.Threading;
moel@191
    45
moel@191
    46
namespace OpenHardwareMonitor.Hardware.CPU {
moel@195
    47
  internal class GenericCPU : Hardware {
moel@191
    48
moel@191
    49
    protected readonly CPUID[][] cpuid;
moel@191
    50
   
moel@191
    51
    protected readonly uint family;
moel@191
    52
    protected readonly uint model;
moel@191
    53
    protected readonly uint stepping;
moel@191
    54
moel@191
    55
    protected readonly int processorIndex;
moel@191
    56
    protected readonly int coreCount;
moel@191
    57
    protected readonly string name;
moel@191
    58
moel@236
    59
    private readonly bool hasModelSpecificRegisters;
moel@236
    60
moel@201
    61
    private readonly bool hasTimeStampCounter;
moel@201
    62
    private readonly bool isInvariantTimeStampCounter;
moel@201
    63
    private readonly double estimatedTimeStampCounterFrequency;
moel@191
    64
moel@191
    65
    private ulong lastTimeStampCount;
moel@191
    66
    private long lastTime;
moel@201
    67
    private double timeStampCounterFrequency;    
moel@191
    68
moel@195
    69
    private readonly Vendor vendor;
moel@191
    70
moel@191
    71
    private readonly CPULoad cpuLoad;
moel@191
    72
    private readonly Sensor totalLoad;
moel@191
    73
    private readonly Sensor[] coreLoads;
moel@191
    74
moel@191
    75
    protected string CoreString(int i) {
moel@191
    76
      if (coreCount == 1)
moel@191
    77
        return "CPU Core";
moel@191
    78
      else
moel@191
    79
        return "CPU Core #" + (i + 1);
moel@191
    80
    }
moel@191
    81
moel@191
    82
    public GenericCPU(int processorIndex, CPUID[][] cpuid, ISettings settings) {
moel@191
    83
      this.cpuid = cpuid;
moel@191
    84
moel@191
    85
      this.vendor = cpuid[0][0].Vendor;
moel@191
    86
moel@191
    87
      this.family = cpuid[0][0].Family;
moel@191
    88
      this.model = cpuid[0][0].Model;
moel@191
    89
      this.stepping = cpuid[0][0].Stepping;
moel@191
    90
moel@191
    91
      this.processorIndex = processorIndex;
moel@191
    92
      this.coreCount = cpuid.Length;
moel@236
    93
      this.name = cpuid[0][0].Name;    
moel@236
    94
  
moel@236
    95
      // check if processor has MSRs
moel@236
    96
      if (cpuid[0][0].Data.GetLength(0) > 1
moel@236
    97
        && (cpuid[0][0].Data[1, 3] & 0x20) != 0)
moel@236
    98
        hasModelSpecificRegisters = true;
moel@236
    99
      else
moel@236
   100
        hasModelSpecificRegisters = false;
moel@191
   101
moel@201
   102
      // check if processor has a TSC
moel@191
   103
      if (cpuid[0][0].Data.GetLength(0) > 1
moel@191
   104
        && (cpuid[0][0].Data[1, 3] & 0x10) != 0)
moel@201
   105
        hasTimeStampCounter = true;
moel@191
   106
      else
moel@201
   107
        hasTimeStampCounter = false;
moel@191
   108
moel@201
   109
      // check if processor supports an invariant TSC 
moel@191
   110
      if (cpuid[0][0].ExtData.GetLength(0) > 7
moel@191
   111
        && (cpuid[0][0].ExtData[7, 3] & 0x100) != 0)
moel@201
   112
        isInvariantTimeStampCounter = true;
moel@191
   113
      else
moel@201
   114
        isInvariantTimeStampCounter = false;
moel@191
   115
moel@191
   116
      if (coreCount > 1)
moel@191
   117
        totalLoad = new Sensor("CPU Total", 0, SensorType.Load, this, settings);
moel@191
   118
      else
moel@191
   119
        totalLoad = null;
moel@191
   120
      coreLoads = new Sensor[coreCount];
moel@191
   121
      for (int i = 0; i < coreLoads.Length; i++)
moel@191
   122
        coreLoads[i] = new Sensor(CoreString(i), i + 1,
moel@191
   123
          SensorType.Load, this, settings);
moel@191
   124
      cpuLoad = new CPULoad(cpuid);
moel@191
   125
      if (cpuLoad.IsAvailable) {
moel@191
   126
        foreach (Sensor sensor in coreLoads)
moel@191
   127
          ActivateSensor(sensor);
moel@191
   128
        if (totalLoad != null)
moel@191
   129
          ActivateSensor(totalLoad);
moel@191
   130
      }
moel@191
   131
moel@203
   132
      if (hasTimeStampCounter) {
moel@238
   133
        ulong mask = ThreadAffinity.Set(1UL << cpuid[0][0].Thread);
moel@238
   134
        
moel@203
   135
        estimatedTimeStampCounterFrequency = 
moel@238
   136
          EstimateTimeStampCounterFrequency();  
moel@238
   137
        
moel@238
   138
        ThreadAffinity.Set(mask);
moel@203
   139
      } else {
moel@201
   140
        estimatedTimeStampCounterFrequency = 0;
moel@203
   141
      }
moel@203
   142
moel@203
   143
      timeStampCounterFrequency = estimatedTimeStampCounterFrequency;                  
moel@191
   144
    }
moel@191
   145
moel@238
   146
    private static double EstimateTimeStampCounterFrequency() {           
moel@191
   147
      // preload the function
moel@201
   148
      EstimateTimeStampCounterFrequency(0);
moel@201
   149
      EstimateTimeStampCounterFrequency(0);
moel@191
   150
moel@201
   151
      // estimate the frequency in MHz      
moel@201
   152
      List<double> estimatedFrequency = new List<double>(3);
moel@191
   153
      for (int i = 0; i < 3; i++)
moel@201
   154
        estimatedFrequency.Add(1e-6 * EstimateTimeStampCounterFrequency(0.025));
moel@238
   155
                 
moel@201
   156
      estimatedFrequency.Sort();
moel@201
   157
      return estimatedFrequency[1];
moel@191
   158
    }
moel@191
   159
moel@201
   160
    private static double EstimateTimeStampCounterFrequency(double timeWindow) {
moel@191
   161
      long ticks = (long)(timeWindow * Stopwatch.Frequency);
moel@236
   162
      ulong countBegin, countEnd;
moel@191
   163
moel@191
   164
      long timeBegin = Stopwatch.GetTimestamp() +
moel@191
   165
        (long)Math.Ceiling(0.001 * ticks);
moel@191
   166
      long timeEnd = timeBegin + ticks;
moel@191
   167
      while (Stopwatch.GetTimestamp() < timeBegin) { }
moel@236
   168
      countBegin = Opcode.Rdtsc();
moel@191
   169
      while (Stopwatch.GetTimestamp() < timeEnd) { }
moel@236
   170
      countEnd = Opcode.Rdtsc();
moel@191
   171
moel@191
   172
      return (((double)(countEnd - countBegin)) * Stopwatch.Frequency) /
moel@191
   173
        (timeEnd - timeBegin);
moel@191
   174
    }
moel@191
   175
moel@236
   176
moel@191
   177
    private static void AppendMSRData(StringBuilder r, uint msr, int thread) {
moel@191
   178
      uint eax, edx;
moel@238
   179
      if (Ring0.RdmsrTx(msr, out eax, out edx, 1UL << thread)) {
moel@191
   180
        r.Append(" ");
moel@191
   181
        r.Append((msr).ToString("X8", CultureInfo.InvariantCulture));
moel@191
   182
        r.Append("  ");
moel@191
   183
        r.Append((edx).ToString("X8", CultureInfo.InvariantCulture));
moel@191
   184
        r.Append("  ");
moel@191
   185
        r.Append((eax).ToString("X8", CultureInfo.InvariantCulture));
moel@191
   186
        r.AppendLine();
moel@191
   187
      }
moel@191
   188
    }
moel@191
   189
moel@191
   190
    protected virtual uint[] GetMSRs() {
moel@191
   191
      return null;
moel@191
   192
    }
moel@191
   193
moel@191
   194
    public override string GetReport() {
moel@191
   195
      StringBuilder r = new StringBuilder();
moel@191
   196
moel@191
   197
      switch (vendor) {
moel@195
   198
        case Vendor.AMD: r.AppendLine("AMD CPU"); break;
moel@191
   199
        case Vendor.Intel: r.AppendLine("Intel CPU"); break;
moel@191
   200
        default: r.AppendLine("Generic CPU"); break;
moel@191
   201
      }
moel@191
   202
moel@191
   203
      r.AppendLine();
moel@191
   204
      r.AppendFormat("Name: {0}{1}", name, Environment.NewLine);
moel@191
   205
      r.AppendFormat("Number of Cores: {0}{1}", coreCount,
moel@191
   206
        Environment.NewLine);
moel@191
   207
      r.AppendFormat("Threads per Core: {0}{1}", cpuid[0].Length,
moel@191
   208
        Environment.NewLine);
moel@191
   209
      r.AppendLine(string.Format(CultureInfo.InvariantCulture,
moel@191
   210
        "Timer Frequency: {0} MHz", Stopwatch.Frequency * 1e-6));
moel@201
   211
      r.AppendLine("Time Stamp Counter: " + (hasTimeStampCounter ? (
moel@201
   212
        isInvariantTimeStampCounter ? "Invariant" : "Not Invariant") : "None"));
moel@191
   213
      r.AppendLine(string.Format(CultureInfo.InvariantCulture,
moel@201
   214
        "Time Stamp Counter Frequency: {0} MHz",
moel@201
   215
        Math.Round(timeStampCounterFrequency * 100) * 0.01));   
moel@191
   216
      r.AppendLine();
moel@191
   217
moel@191
   218
      uint[] msrArray = GetMSRs();
moel@191
   219
      if (msrArray != null && msrArray.Length > 0) {
moel@191
   220
        for (int i = 0; i < cpuid.Length; i++) {
moel@191
   221
          r.AppendLine("MSR Core #" + (i + 1));
moel@191
   222
          r.AppendLine();
moel@191
   223
          r.AppendLine(" MSR       EDX       EAX");
moel@191
   224
          foreach (uint msr in msrArray)
moel@191
   225
            AppendMSRData(r, msr, cpuid[i][0].Thread);
moel@191
   226
          r.AppendLine();
moel@191
   227
        }
moel@191
   228
      }
moel@191
   229
moel@191
   230
      return r.ToString();
moel@191
   231
    }
moel@191
   232
moel@191
   233
    public override Identifier Identifier {
moel@191
   234
      get {
moel@191
   235
        string s;
moel@191
   236
        switch (vendor) {
moel@191
   237
          case Vendor.AMD: s = "amdcpu"; break;
moel@191
   238
          case Vendor.Intel: s = "intelcpu"; break;
moel@191
   239
          default: s = "genericcpu"; break;
moel@191
   240
        }
moel@191
   241
        return new Identifier(s, 
moel@191
   242
          processorIndex.ToString(CultureInfo.InvariantCulture));
moel@191
   243
      }
moel@191
   244
    }
moel@191
   245
moel@191
   246
    public override string Name {
moel@191
   247
      get { return name; }
moel@191
   248
    }
moel@191
   249
moel@191
   250
    public override HardwareType HardwareType {
moel@191
   251
      get { return HardwareType.CPU; }
moel@191
   252
    }
moel@191
   253
moel@236
   254
    public bool HasModelSpecificRegisters {
moel@236
   255
      get { return hasModelSpecificRegisters; }
moel@236
   256
    }
moel@236
   257
moel@201
   258
    public bool HasTimeStampCounter {
moel@201
   259
      get { return hasTimeStampCounter; }
moel@201
   260
    }
moel@201
   261
moel@201
   262
    public double TimeStampCounterFrequency {
moel@201
   263
      get { return timeStampCounterFrequency; }
moel@191
   264
    }
moel@191
   265
moel@191
   266
    public override void Update() {
moel@222
   267
      if (hasTimeStampCounter && isInvariantTimeStampCounter) {
moel@236
   268
moel@236
   269
        // make sure always the same thread is used
moel@238
   270
        ulong mask = ThreadAffinity.Set(1UL << cpuid[0][0].Thread);
moel@222
   271
moel@222
   272
        // read time before and after getting the TSC to estimate the error
moel@222
   273
        long firstTime = Stopwatch.GetTimestamp();
moel@236
   274
        ulong timeStampCount = Opcode.Rdtsc();
moel@191
   275
        long time = Stopwatch.GetTimestamp();
moel@222
   276
moel@236
   277
        // restore the thread affinity mask
moel@238
   278
        ThreadAffinity.Set(mask);
moel@236
   279
moel@191
   280
        double delta = ((double)(time - lastTime)) / Stopwatch.Frequency;
moel@222
   281
        double error = ((double)(time - firstTime)) / Stopwatch.Frequency;
moel@222
   282
moel@222
   283
        // only use data if they are measured accuarte enough (max 0.1ms delay)
moel@222
   284
        if (error < 0.0001) {
moel@222
   285
moel@222
   286
          // ignore the first reading because there are no initial values 
moel@222
   287
          // ignore readings with too large or too small time window
moel@222
   288
          if (lastTime != 0 && delta > 0.5 && delta < 2) {
moel@222
   289
moel@222
   290
            // update the TSC frequency with the new value
moel@222
   291
            timeStampCounterFrequency =
moel@201
   292
              (timeStampCount - lastTimeStampCount) / (1e6 * delta);
moel@222
   293
          }
moel@191
   294
moel@191
   295
          lastTimeStampCount = timeStampCount;
moel@191
   296
          lastTime = time;
moel@191
   297
        }        
moel@191
   298
      }
moel@191
   299
moel@191
   300
      if (cpuLoad.IsAvailable) {
moel@191
   301
        cpuLoad.Update();
moel@191
   302
        for (int i = 0; i < coreLoads.Length; i++)
moel@191
   303
          coreLoads[i].Value = cpuLoad.GetCoreLoad(i);
moel@191
   304
        if (totalLoad != null)
moel@191
   305
          totalLoad.Value = cpuLoad.GetTotalLoad();
moel@191
   306
      }
moel@191
   307
    }
moel@191
   308
  }
moel@191
   309
}