Hardware/CPU/AMD10CPU.cs
author sl
Sun, 03 Feb 2013 18:01:50 +0100
changeset 391 ca4c0e7ae75d
parent 329 756af5ee409e
permissions -rw-r--r--
Converted project to VisualStudio 2012.
Adding SoundGraphDisplay and SensorFrontView classes.
They were respectively based on SystemTray and SensorNotifyIcon.
SoundGraphDisplay is now able to load iMONDisplay.dll providing it lives on your PATH.
Adding option to sensor context menu for adding it into FrontView.
moel@1
     1
/*
moel@1
     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@1
     6
 
moel@344
     7
  Copyright (C) 2009-2011 Michael Möller <mmoeller@openhardwaremonitor.org>
moel@344
     8
	
moel@1
     9
*/
moel@1
    10
moel@196
    11
using System;
moel@201
    12
using System.Collections.Generic;
moel@201
    13
using System.Diagnostics;
moel@196
    14
using System.Globalization;
moel@268
    15
using System.IO;
moel@201
    16
using System.Runtime.InteropServices;
moel@196
    17
using System.Text;
moel@197
    18
using System.Threading;
moel@196
    19
moel@1
    20
namespace OpenHardwareMonitor.Hardware.CPU {
moel@165
    21
moel@196
    22
  internal sealed class AMD10CPU : AMDCPU {
moel@1
    23
moel@195
    24
    private readonly Sensor coreTemperature;
moel@197
    25
    private readonly Sensor[] coreClocks;
moel@197
    26
    private readonly Sensor busClock;
moel@201
    27
      
moel@201
    28
    private const uint PERF_CTL_0 = 0xC0010000;
moel@201
    29
    private const uint PERF_CTR_0 = 0xC0010004;
moel@279
    30
    private const uint HWCR = 0xC0010015;
moel@201
    31
    private const uint P_STATE_0 = 0xC0010064;
moel@197
    32
    private const uint COFVID_STATUS = 0xC0010071;
moel@1
    33
moel@196
    34
    private const byte MISCELLANEOUS_CONTROL_FUNCTION = 3;
moel@251
    35
    private const ushort FAMILY_10H_MISCELLANEOUS_CONTROL_DEVICE_ID = 0x1203;
moel@271
    36
    private const ushort FAMILY_11H_MISCELLANEOUS_CONTROL_DEVICE_ID = 0x1303;
moel@301
    37
    private const ushort FAMILY_12H_MISCELLANEOUS_CONTROL_DEVICE_ID = 0x1703;
moel@301
    38
    private const ushort FAMILY_14H_MISCELLANEOUS_CONTROL_DEVICE_ID = 0x1703;
moel@301
    39
    private const ushort FAMILY_15H_MISCELLANEOUS_CONTROL_DEVICE_ID = 0x1603; 
moel@197
    40
    private const uint REPORTED_TEMPERATURE_CONTROL_REGISTER = 0xA4;
moel@273
    41
    private const uint CLOCK_POWER_TIMING_CONTROL_0_REGISTER = 0xD4;
moel@201
    42
moel@196
    43
    private readonly uint miscellaneousControlAddress;
moel@251
    44
    private readonly ushort miscellaneousControlDeviceId;
moel@1
    45
moel@268
    46
    private readonly FileStream temperatureStream;
moel@266
    47
moel@279
    48
    private readonly double timeStampCounterMultiplier;
moel@279
    49
    private readonly bool corePerformanceBoostSupport;
moel@201
    50
moel@191
    51
    public AMD10CPU(int processorIndex, CPUID[][] cpuid, ISettings settings)
moel@191
    52
      : base(processorIndex, cpuid, settings) 
moel@196
    53
    {            
moel@301
    54
      // AMD family 1Xh processors support only one temperature sensor
moel@22
    55
      coreTemperature = new Sensor(
moel@134
    56
        "Core" + (coreCount > 1 ? " #1 - #" + coreCount : ""), 0,
moel@195
    57
        SensorType.Temperature, this, new [] {
moel@122
    58
            new ParameterDescription("Offset [°C]", "Temperature offset.", 0)
moel@165
    59
          }, settings);
moel@1
    60
moel@251
    61
      switch (family) {
moel@251
    62
        case 0x10: miscellaneousControlDeviceId =
moel@251
    63
          FAMILY_10H_MISCELLANEOUS_CONTROL_DEVICE_ID; break;
moel@251
    64
        case 0x11: miscellaneousControlDeviceId =
moel@251
    65
          FAMILY_11H_MISCELLANEOUS_CONTROL_DEVICE_ID; break;
moel@301
    66
        case 0x12: miscellaneousControlDeviceId =
moel@301
    67
          FAMILY_12H_MISCELLANEOUS_CONTROL_DEVICE_ID; break;
moel@271
    68
        case 0x14: miscellaneousControlDeviceId = 
moel@273
    69
          FAMILY_14H_MISCELLANEOUS_CONTROL_DEVICE_ID; break;
moel@301
    70
        case 0x15: miscellaneousControlDeviceId =
moel@301
    71
          FAMILY_15H_MISCELLANEOUS_CONTROL_DEVICE_ID; break;
moel@251
    72
        default: miscellaneousControlDeviceId = 0; break;
moel@251
    73
      }
moel@251
    74
moel@196
    75
      // get the pci address for the Miscellaneous Control registers 
moel@196
    76
      miscellaneousControlAddress = GetPciAddress(
moel@251
    77
        MISCELLANEOUS_CONTROL_FUNCTION, miscellaneousControlDeviceId);        
moel@42
    78
moel@197
    79
      busClock = new Sensor("Bus Speed", 0, SensorType.Clock, this, settings);
moel@197
    80
      coreClocks = new Sensor[coreCount];
moel@197
    81
      for (int i = 0; i < coreClocks.Length; i++) {
moel@197
    82
        coreClocks[i] = new Sensor(CoreString(i), i + 1, SensorType.Clock,
moel@197
    83
          this, settings);
moel@201
    84
        if (HasTimeStampCounter)
moel@197
    85
          ActivateSensor(coreClocks[i]);
moel@197
    86
      }
moel@197
    87
moel@279
    88
      corePerformanceBoostSupport = (cpuid[0][0].ExtData[7, 3] & (1 << 9)) > 0;
moel@279
    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@279
    93
      // disable core performance boost  
moel@279
    94
      uint hwcrEax, hwcrEdx;
moel@279
    95
      Ring0.Rdmsr(HWCR, out hwcrEax, out hwcrEdx);
moel@279
    96
      if (corePerformanceBoostSupport) 
moel@279
    97
        Ring0.Wrmsr(HWCR, hwcrEax | (1 << 25), hwcrEdx);
moel@279
    98
moel@201
    99
      uint ctlEax, ctlEdx;
moel@236
   100
      Ring0.Rdmsr(PERF_CTL_0, out ctlEax, out ctlEdx);
moel@201
   101
      uint ctrEax, ctrEdx;
moel@236
   102
      Ring0.Rdmsr(PERF_CTR_0, out ctrEax, out ctrEdx);
moel@201
   103
moel@201
   104
      timeStampCounterMultiplier = estimateTimeStampCounterMultiplier();
moel@201
   105
moel@201
   106
      // restore the performance counter registers
moel@236
   107
      Ring0.Wrmsr(PERF_CTL_0, ctlEax, ctlEdx);
moel@236
   108
      Ring0.Wrmsr(PERF_CTR_0, ctrEax, ctrEdx);
moel@201
   109
moel@279
   110
      // restore core performance boost
moel@279
   111
      if (corePerformanceBoostSupport)     
moel@279
   112
        Ring0.Wrmsr(HWCR, hwcrEax, hwcrEdx);
moel@279
   113
moel@201
   114
      // restore the thread affinity.
moel@238
   115
      ThreadAffinity.Set(mask);
moel@201
   116
moel@266
   117
      // the file reader for lm-sensors support on Linux
moel@268
   118
      temperatureStream = null;
moel@266
   119
      int p = (int)Environment.OSVersion.Platform;
moel@266
   120
      if ((p == 4) || (p == 128)) {
moel@266
   121
        string[] devicePaths = Directory.GetDirectories("/sys/class/hwmon/");
moel@266
   122
        foreach (string path in devicePaths) {
moel@266
   123
          string name = null;
moel@266
   124
          try {
moel@266
   125
            using (StreamReader reader = new StreamReader(path + "/device/name"))
moel@266
   126
              name = reader.ReadLine();
moel@266
   127
          } catch (IOException) { }
moel@266
   128
          switch (name) {
moel@266
   129
            case "k10temp":
moel@268
   130
              temperatureStream = new FileStream(path + "/device/temp1_input", 
moel@268
   131
                FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
moel@266
   132
              break;
moel@266
   133
          }
moel@266
   134
        }
moel@266
   135
      }
moel@266
   136
moel@1
   137
      Update();                   
moel@1
   138
    }
moel@1
   139
moel@201
   140
    private double estimateTimeStampCounterMultiplier() {
moel@201
   141
      // preload the function
moel@201
   142
      estimateTimeStampCounterMultiplier(0);
moel@201
   143
      estimateTimeStampCounterMultiplier(0);
moel@201
   144
moel@201
   145
      // estimate the multiplier
moel@201
   146
      List<double> estimate = new List<double>(3);
moel@201
   147
      for (int i = 0; i < 3; i++)
moel@201
   148
        estimate.Add(estimateTimeStampCounterMultiplier(0.025));
moel@201
   149
      estimate.Sort();
moel@201
   150
      return estimate[1];
moel@201
   151
    }
moel@201
   152
moel@201
   153
    private double estimateTimeStampCounterMultiplier(double timeWindow) {
moel@201
   154
      uint eax, edx;
moel@201
   155
     
moel@201
   156
      // select event "076h CPU Clocks not Halted" and enable the counter
moel@236
   157
      Ring0.Wrmsr(PERF_CTL_0,
moel@201
   158
        (1 << 22) | // enable performance counter
moel@201
   159
        (1 << 17) | // count events in user mode
moel@201
   160
        (1 << 16) | // count events in operating-system mode
moel@201
   161
        0x76, 0x00000000);
moel@201
   162
moel@201
   163
      // set the counter to 0
moel@236
   164
      Ring0.Wrmsr(PERF_CTR_0, 0, 0);
moel@201
   165
moel@201
   166
      long ticks = (long)(timeWindow * Stopwatch.Frequency);
moel@273
   167
      uint lsbBegin, msbBegin, lsbEnd, msbEnd;      
moel@201
   168
moel@201
   169
      long timeBegin = Stopwatch.GetTimestamp() +
moel@201
   170
        (long)Math.Ceiling(0.001 * ticks);
moel@201
   171
      long timeEnd = timeBegin + ticks;
moel@201
   172
      while (Stopwatch.GetTimestamp() < timeBegin) { }
moel@236
   173
      Ring0.Rdmsr(PERF_CTR_0, out lsbBegin, out msbBegin);
moel@279
   174
moel@201
   175
      while (Stopwatch.GetTimestamp() < timeEnd) { }
moel@236
   176
      Ring0.Rdmsr(PERF_CTR_0, out lsbEnd, out msbEnd);
moel@279
   177
      Ring0.Rdmsr(COFVID_STATUS, out eax, out edx);
moel@301
   178
      double coreMultiplier = GetCoreMultiplier(eax);
moel@201
   179
moel@201
   180
      ulong countBegin = ((ulong)msbBegin << 32) | lsbBegin;
moel@201
   181
      ulong countEnd = ((ulong)msbEnd << 32) | lsbEnd;
moel@201
   182
moel@201
   183
      double coreFrequency = 1e-6 * 
moel@201
   184
        (((double)(countEnd - countBegin)) * Stopwatch.Frequency) /
moel@201
   185
        (timeEnd - timeBegin);
moel@201
   186
moel@201
   187
      double busFrequency = coreFrequency / coreMultiplier;
moel@279
   188
moel@273
   189
      return 0.25 * Math.Round(4 * TimeStampCounterFrequency / busFrequency);
moel@201
   190
    }
moel@201
   191
moel@191
   192
    protected override uint[] GetMSRs() {
moel@279
   193
      return new uint[] { PERF_CTL_0, PERF_CTR_0, HWCR, P_STATE_0, 
moel@279
   194
        COFVID_STATUS };
moel@1
   195
    }
moel@1
   196
moel@196
   197
    public override string GetReport() {
moel@196
   198
      StringBuilder r = new StringBuilder();
moel@196
   199
      r.Append(base.GetReport());
moel@196
   200
moel@197
   201
      r.Append("Miscellaneous Control Address: 0x");
moel@196
   202
      r.AppendLine((miscellaneousControlAddress).ToString("X",
moel@196
   203
        CultureInfo.InvariantCulture));
moel@201
   204
      r.Append("Time Stamp Counter Multiplier: ");
moel@201
   205
      r.AppendLine(timeStampCounterMultiplier.ToString(
moel@201
   206
        CultureInfo.InvariantCulture));
moel@273
   207
      if (family == 0x14) {
moel@273
   208
        uint value = 0;
moel@273
   209
        Ring0.ReadPciConfig(miscellaneousControlAddress,
moel@273
   210
          CLOCK_POWER_TIMING_CONTROL_0_REGISTER, out value);
moel@273
   211
        r.Append("PCI Register D18F3xD4: ");
moel@273
   212
        r.AppendLine(value.ToString("X8", CultureInfo.InvariantCulture));
moel@273
   213
      }
moel@201
   214
      r.AppendLine();
moel@201
   215
moel@196
   216
      return r.ToString();
moel@196
   217
    }
moel@196
   218
moel@301
   219
    private double GetCoreMultiplier(uint cofvidEax) {
moel@301
   220
      switch (family) {
moel@301
   221
        case 0x10:
moel@329
   222
        case 0x11: 
moel@329
   223
        case 0x15: {
moel@329
   224
            // 8:6 CpuDid: current core divisor ID
moel@329
   225
            // 5:0 CpuFid: current core frequency ID
moel@329
   226
            uint cpuDid = (cofvidEax >> 6) & 7;
moel@329
   227
            uint cpuFid = cofvidEax & 0x1F;
moel@329
   228
            return 0.5 * (cpuFid + 0x10) / (1 << (int)cpuDid);
moel@301
   229
          }
moel@329
   230
        case 0x12: {
moel@329
   231
            // 8:4 CpuFid: current CPU core frequency ID
moel@329
   232
            // 3:0 CpuDid: current CPU core divisor ID
moel@329
   233
            uint cpuFid = (cofvidEax >> 4) & 0x1F;
moel@329
   234
            uint cpuDid = cofvidEax & 0xF;
moel@329
   235
            double divisor;
moel@329
   236
            switch (cpuDid) {
moel@329
   237
              case 0: divisor = 1; break;
moel@329
   238
              case 1: divisor = 1.5; break;
moel@329
   239
              case 2: divisor = 2; break;
moel@329
   240
              case 3: divisor = 3; break;
moel@329
   241
              case 4: divisor = 4; break;
moel@329
   242
              case 5: divisor = 6; break;
moel@329
   243
              case 6: divisor = 8; break;
moel@329
   244
              case 7: divisor = 12; break;
moel@329
   245
              case 8: divisor = 16; break;
moel@329
   246
              default: divisor = 1; break;
moel@329
   247
            }
moel@329
   248
            return (cpuFid + 0x10) / divisor;
moel@329
   249
          }
moel@329
   250
        case 0x14: {
moel@329
   251
            // 8:4: current CPU core divisor ID most significant digit
moel@329
   252
            // 3:0: current CPU core divisor ID least significant digit
moel@329
   253
            uint divisorIdMSD = (cofvidEax >> 4) & 0x1F;
moel@329
   254
            uint divisorIdLSD = cofvidEax & 0xF;
moel@329
   255
            uint value = 0;
moel@329
   256
            Ring0.ReadPciConfig(miscellaneousControlAddress,
moel@329
   257
              CLOCK_POWER_TIMING_CONTROL_0_REGISTER, out value);
moel@329
   258
            uint frequencyId = value & 0x1F;
moel@329
   259
            return (frequencyId + 0x10) /
moel@329
   260
              (divisorIdMSD + (divisorIdLSD * 0.25) + 1);
moel@329
   261
          }
moel@301
   262
        default:
moel@301
   263
          return 1;
moel@301
   264
      }
moel@273
   265
    }
moel@273
   266
moel@268
   267
    private string ReadFirstLine(Stream stream) {
moel@268
   268
      StringBuilder sb = new StringBuilder();
moel@268
   269
      try {
moel@268
   270
        stream.Seek(0, SeekOrigin.Begin);
moel@268
   271
        int b = stream.ReadByte();
moel@268
   272
        while (b != -1 && b != 10) {
moel@268
   273
          sb.Append((char)b);
moel@268
   274
          b = stream.ReadByte();
moel@268
   275
        }
moel@268
   276
      } catch { }
moel@268
   277
      return sb.ToString();
moel@268
   278
    }
moel@268
   279
moel@110
   280
    public override void Update() {
moel@191
   281
      base.Update();
moel@191
   282
moel@268
   283
      if (temperatureStream == null) {
moel@266
   284
        if (miscellaneousControlAddress != Ring0.InvalidPciAddress) {
moel@266
   285
          uint value;
moel@266
   286
          if (Ring0.ReadPciConfig(miscellaneousControlAddress,
moel@266
   287
            REPORTED_TEMPERATURE_CONTROL_REGISTER, out value)) {
moel@329
   288
            if (family == 0x15 && (value & 0x30000) == 0x30000) {
moel@329
   289
              coreTemperature.Value = ((value >> 21) & 0x7FC) / 8.0f +
moel@329
   290
                coreTemperature.Parameters[0].Value - 49;
moel@329
   291
            } else {
moel@329
   292
              coreTemperature.Value = ((value >> 21) & 0x7FF) / 8.0f +
moel@329
   293
                coreTemperature.Parameters[0].Value;
moel@329
   294
            }
moel@266
   295
            ActivateSensor(coreTemperature);
moel@266
   296
          } else {
moel@266
   297
            DeactivateSensor(coreTemperature);
moel@266
   298
          }
moel@266
   299
        }
moel@266
   300
      } else {
moel@268
   301
        string s = ReadFirstLine(temperatureStream);
moel@266
   302
        try {
moel@266
   303
          coreTemperature.Value = 0.001f *
moel@266
   304
            long.Parse(s, CultureInfo.InvariantCulture);
moel@42
   305
          ActivateSensor(coreTemperature);
moel@266
   306
        } catch {
moel@42
   307
          DeactivateSensor(coreTemperature);
moel@266
   308
        }        
moel@24
   309
      }
moel@197
   310
moel@201
   311
      if (HasTimeStampCounter) {
moel@197
   312
        double newBusClock = 0;
moel@197
   313
moel@197
   314
        for (int i = 0; i < coreClocks.Length; i++) {
moel@197
   315
          Thread.Sleep(1);
moel@197
   316
moel@197
   317
          uint curEax, curEdx;
moel@236
   318
          if (Ring0.RdmsrTx(COFVID_STATUS, out curEax, out curEdx,
moel@238
   319
            1UL << cpuid[i][0].Thread)) 
moel@197
   320
          {
moel@273
   321
            double multiplier;
moel@301
   322
            multiplier = GetCoreMultiplier(curEax);
moel@197
   323
moel@201
   324
            coreClocks[i].Value = 
moel@201
   325
              (float)(multiplier * TimeStampCounterFrequency / 
moel@201
   326
              timeStampCounterMultiplier);
moel@201
   327
            newBusClock = 
moel@201
   328
              (float)(TimeStampCounterFrequency / timeStampCounterMultiplier);
moel@197
   329
          } else {
moel@201
   330
            coreClocks[i].Value = (float)TimeStampCounterFrequency;
moel@197
   331
          }
moel@197
   332
        }
moel@197
   333
moel@197
   334
        if (newBusClock > 0) {
moel@197
   335
          this.busClock.Value = (float)newBusClock;
moel@197
   336
          ActivateSensor(this.busClock);
moel@197
   337
        }
moel@197
   338
      }
moel@201
   339
    }
moel@266
   340
moel@298
   341
    public override void Close() {      
moel@268
   342
      if (temperatureStream != null) {
moel@268
   343
        temperatureStream.Close();
moel@266
   344
      }
moel@298
   345
      base.Close();
moel@266
   346
    }
moel@1
   347
  }
moel@1
   348
}