Hardware/CPU/AMD10CPU.cs
author moel.mich
Thu, 11 Nov 2010 21:22:24 +0000
changeset 241 52007c404f32
parent 236 763675f19ff4
child 251 49c38a2958c8
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@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@196
    38
using System;
moel@201
    39
using System.Collections.Generic;
moel@201
    40
using System.Diagnostics;
moel@196
    41
using System.Globalization;
moel@201
    42
using System.Runtime.InteropServices;
moel@196
    43
using System.Text;
moel@197
    44
using System.Threading;
moel@196
    45
moel@1
    46
namespace OpenHardwareMonitor.Hardware.CPU {
moel@165
    47
moel@196
    48
  internal sealed class AMD10CPU : AMDCPU {
moel@1
    49
moel@195
    50
    private readonly Sensor coreTemperature;
moel@197
    51
    private readonly Sensor[] coreClocks;
moel@197
    52
    private readonly Sensor busClock;
moel@201
    53
      
moel@201
    54
    private const uint PERF_CTL_0 = 0xC0010000;
moel@201
    55
    private const uint PERF_CTR_0 = 0xC0010004;
moel@201
    56
    private const uint P_STATE_0 = 0xC0010064;
moel@197
    57
    private const uint COFVID_STATUS = 0xC0010071;
moel@1
    58
moel@196
    59
    private const byte MISCELLANEOUS_CONTROL_FUNCTION = 3;
moel@196
    60
    private const ushort MISCELLANEOUS_CONTROL_DEVICE_ID = 0x1203;
moel@197
    61
    private const uint REPORTED_TEMPERATURE_CONTROL_REGISTER = 0xA4;
moel@201
    62
moel@196
    63
    private readonly uint miscellaneousControlAddress;
moel@1
    64
moel@201
    65
    private double timeStampCounterMultiplier;
moel@201
    66
moel@191
    67
    public AMD10CPU(int processorIndex, CPUID[][] cpuid, ISettings settings)
moel@191
    68
      : base(processorIndex, cpuid, settings) 
moel@196
    69
    {            
moel@1
    70
      // AMD family 10h processors support only one temperature sensor
moel@22
    71
      coreTemperature = new Sensor(
moel@134
    72
        "Core" + (coreCount > 1 ? " #1 - #" + coreCount : ""), 0,
moel@195
    73
        SensorType.Temperature, this, new [] {
moel@122
    74
            new ParameterDescription("Offset [°C]", "Temperature offset.", 0)
moel@165
    75
          }, settings);
moel@1
    76
moel@196
    77
      // get the pci address for the Miscellaneous Control registers 
moel@196
    78
      miscellaneousControlAddress = GetPciAddress(
moel@196
    79
        MISCELLANEOUS_CONTROL_FUNCTION, MISCELLANEOUS_CONTROL_DEVICE_ID);
moel@42
    80
moel@197
    81
      busClock = new Sensor("Bus Speed", 0, SensorType.Clock, this, settings);
moel@197
    82
      coreClocks = new Sensor[coreCount];
moel@197
    83
      for (int i = 0; i < coreClocks.Length; i++) {
moel@197
    84
        coreClocks[i] = new Sensor(CoreString(i), i + 1, SensorType.Clock,
moel@197
    85
          this, settings);
moel@201
    86
        if (HasTimeStampCounter)
moel@197
    87
          ActivateSensor(coreClocks[i]);
moel@197
    88
      }
moel@197
    89
moel@238
    90
      // set affinity to the first thread for all frequency estimations     
moel@238
    91
      ulong mask = ThreadAffinity.Set(1UL << cpuid[0][0].Thread);
moel@201
    92
moel@201
    93
      uint ctlEax, ctlEdx;
moel@236
    94
      Ring0.Rdmsr(PERF_CTL_0, out ctlEax, out ctlEdx);
moel@201
    95
      uint ctrEax, ctrEdx;
moel@236
    96
      Ring0.Rdmsr(PERF_CTR_0, out ctrEax, out ctrEdx);
moel@201
    97
moel@201
    98
      timeStampCounterMultiplier = estimateTimeStampCounterMultiplier();
moel@201
    99
moel@201
   100
      // restore the performance counter registers
moel@236
   101
      Ring0.Wrmsr(PERF_CTL_0, ctlEax, ctlEdx);
moel@236
   102
      Ring0.Wrmsr(PERF_CTR_0, ctrEax, ctrEdx);
moel@201
   103
moel@201
   104
      // restore the thread affinity.
moel@238
   105
      ThreadAffinity.Set(mask);
moel@201
   106
moel@1
   107
      Update();                   
moel@1
   108
    }
moel@1
   109
moel@201
   110
    private double estimateTimeStampCounterMultiplier() {
moel@201
   111
      // preload the function
moel@201
   112
      estimateTimeStampCounterMultiplier(0);
moel@201
   113
      estimateTimeStampCounterMultiplier(0);
moel@201
   114
moel@201
   115
      // estimate the multiplier
moel@201
   116
      List<double> estimate = new List<double>(3);
moel@201
   117
      for (int i = 0; i < 3; i++)
moel@201
   118
        estimate.Add(estimateTimeStampCounterMultiplier(0.025));
moel@201
   119
      estimate.Sort();
moel@201
   120
      return estimate[1];
moel@201
   121
    }
moel@201
   122
moel@201
   123
    private double estimateTimeStampCounterMultiplier(double timeWindow) {
moel@201
   124
      uint eax, edx;
moel@201
   125
     
moel@201
   126
      // select event "076h CPU Clocks not Halted" and enable the counter
moel@236
   127
      Ring0.Wrmsr(PERF_CTL_0,
moel@201
   128
        (1 << 22) | // enable performance counter
moel@201
   129
        (1 << 17) | // count events in user mode
moel@201
   130
        (1 << 16) | // count events in operating-system mode
moel@201
   131
        0x76, 0x00000000);
moel@201
   132
moel@201
   133
      // set the counter to 0
moel@236
   134
      Ring0.Wrmsr(PERF_CTR_0, 0, 0);
moel@201
   135
moel@201
   136
      long ticks = (long)(timeWindow * Stopwatch.Frequency);
moel@201
   137
      uint lsbBegin, msbBegin, lsbEnd, msbEnd;
moel@201
   138
moel@201
   139
      long timeBegin = Stopwatch.GetTimestamp() +
moel@201
   140
        (long)Math.Ceiling(0.001 * ticks);
moel@201
   141
      long timeEnd = timeBegin + ticks;
moel@201
   142
      while (Stopwatch.GetTimestamp() < timeBegin) { }
moel@236
   143
      Ring0.Rdmsr(PERF_CTR_0, out lsbBegin, out msbBegin);
moel@201
   144
      while (Stopwatch.GetTimestamp() < timeEnd) { }
moel@236
   145
      Ring0.Rdmsr(PERF_CTR_0, out lsbEnd, out msbEnd);
moel@201
   146
moel@236
   147
      Ring0.Rdmsr(COFVID_STATUS, out eax, out edx);
moel@201
   148
      uint cpuDid = (eax >> 6) & 7;
moel@201
   149
      uint cpuFid = eax & 0x1F;
moel@201
   150
      double coreMultiplier = MultiplierFromIDs(cpuDid, cpuFid);
moel@201
   151
moel@201
   152
      ulong countBegin = ((ulong)msbBegin << 32) | lsbBegin;
moel@201
   153
      ulong countEnd = ((ulong)msbEnd << 32) | lsbEnd;
moel@201
   154
moel@201
   155
      double coreFrequency = 1e-6 * 
moel@201
   156
        (((double)(countEnd - countBegin)) * Stopwatch.Frequency) /
moel@201
   157
        (timeEnd - timeBegin);
moel@201
   158
moel@201
   159
      double busFrequency = coreFrequency / coreMultiplier;
moel@201
   160
      return 0.5 * Math.Round(2 * TimeStampCounterFrequency / busFrequency);
moel@201
   161
    }
moel@201
   162
moel@191
   163
    protected override uint[] GetMSRs() {
moel@201
   164
      return new uint[] { PERF_CTL_0, PERF_CTR_0, P_STATE_0, COFVID_STATUS };
moel@1
   165
    }
moel@1
   166
moel@196
   167
    public override string GetReport() {
moel@196
   168
      StringBuilder r = new StringBuilder();
moel@196
   169
      r.Append(base.GetReport());
moel@196
   170
moel@197
   171
      r.Append("Miscellaneous Control Address: 0x");
moel@196
   172
      r.AppendLine((miscellaneousControlAddress).ToString("X",
moel@196
   173
        CultureInfo.InvariantCulture));
moel@201
   174
      r.Append("Time Stamp Counter Multiplier: ");
moel@201
   175
      r.AppendLine(timeStampCounterMultiplier.ToString(
moel@201
   176
        CultureInfo.InvariantCulture));
moel@201
   177
      r.AppendLine();
moel@201
   178
moel@196
   179
      return r.ToString();
moel@196
   180
    }
moel@196
   181
moel@201
   182
    private static double MultiplierFromIDs(uint divisorID, uint frequencyID) {
moel@197
   183
      return 0.5 * (frequencyID + 0x10) / (1 << (int)divisorID);
moel@197
   184
    }
moel@197
   185
moel@110
   186
    public override void Update() {
moel@191
   187
      base.Update();
moel@191
   188
moel@236
   189
      if (miscellaneousControlAddress != Ring0.InvalidPciAddress) {
moel@42
   190
        uint value;
moel@236
   191
        if (Ring0.ReadPciConfig(miscellaneousControlAddress,
moel@42
   192
          REPORTED_TEMPERATURE_CONTROL_REGISTER, out value)) {
moel@63
   193
          coreTemperature.Value = ((value >> 21) & 0x7FF) / 8.0f +
moel@63
   194
            coreTemperature.Parameters[0].Value;
moel@42
   195
          ActivateSensor(coreTemperature);
moel@42
   196
        } else {
moel@42
   197
          DeactivateSensor(coreTemperature);
moel@42
   198
        }
moel@24
   199
      }
moel@197
   200
moel@201
   201
      if (HasTimeStampCounter) {
moel@197
   202
        double newBusClock = 0;
moel@197
   203
moel@197
   204
        for (int i = 0; i < coreClocks.Length; i++) {
moel@197
   205
          Thread.Sleep(1);
moel@197
   206
moel@197
   207
          uint curEax, curEdx;
moel@236
   208
          if (Ring0.RdmsrTx(COFVID_STATUS, out curEax, out curEdx,
moel@238
   209
            1UL << cpuid[i][0].Thread)) 
moel@197
   210
          {
moel@197
   211
            // 8:6 CpuDid: current core divisor ID
moel@197
   212
            // 5:0 CpuFid: current core frequency ID
moel@201
   213
            uint cpuDid = (curEax >> 6) & 7;
moel@201
   214
            uint cpuFid = curEax & 0x1F;
moel@201
   215
            double multiplier = MultiplierFromIDs(cpuDid, cpuFid);
moel@197
   216
moel@201
   217
            coreClocks[i].Value = 
moel@201
   218
              (float)(multiplier * TimeStampCounterFrequency / 
moel@201
   219
              timeStampCounterMultiplier);
moel@201
   220
            newBusClock = 
moel@201
   221
              (float)(TimeStampCounterFrequency / timeStampCounterMultiplier);
moel@197
   222
          } else {
moel@201
   223
            coreClocks[i].Value = (float)TimeStampCounterFrequency;
moel@197
   224
          }
moel@197
   225
        }
moel@197
   226
moel@197
   227
        if (newBusClock > 0) {
moel@197
   228
          this.busClock.Value = (float)newBusClock;
moel@197
   229
          ActivateSensor(this.busClock);
moel@197
   230
        }
moel@197
   231
      }
moel@201
   232
    }
moel@1
   233
  }
moel@1
   234
}