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