Fixed the bus and core clock reading on AMD family 10h model Ah CPUs. The new "Core Performance Boost" feature of these CPUs resulted in very low accuracy of the bus speed (and as a consequence also an inaccurate TSC multiplier). This fixed Issue 205.
This commit is contained in:
@@ -54,6 +54,7 @@ namespace OpenHardwareMonitor.Hardware.CPU {
|
||||
|
||||
private const uint PERF_CTL_0 = 0xC0010000;
|
||||
private const uint PERF_CTR_0 = 0xC0010004;
|
||||
private const uint HWCR = 0xC0010015;
|
||||
private const uint P_STATE_0 = 0xC0010064;
|
||||
private const uint COFVID_STATUS = 0xC0010071;
|
||||
|
||||
@@ -69,7 +70,8 @@ namespace OpenHardwareMonitor.Hardware.CPU {
|
||||
|
||||
private readonly FileStream temperatureStream;
|
||||
|
||||
private double timeStampCounterMultiplier;
|
||||
private readonly double timeStampCounterMultiplier;
|
||||
private readonly bool corePerformanceBoostSupport;
|
||||
|
||||
public AMD10CPU(int processorIndex, CPUID[][] cpuid, ISettings settings)
|
||||
: base(processorIndex, cpuid, settings)
|
||||
@@ -104,9 +106,17 @@ namespace OpenHardwareMonitor.Hardware.CPU {
|
||||
ActivateSensor(coreClocks[i]);
|
||||
}
|
||||
|
||||
corePerformanceBoostSupport = (cpuid[0][0].ExtData[7, 3] & (1 << 9)) > 0;
|
||||
|
||||
// set affinity to the first thread for all frequency estimations
|
||||
ulong mask = ThreadAffinity.Set(1UL << cpuid[0][0].Thread);
|
||||
|
||||
// disable core performance boost
|
||||
uint hwcrEax, hwcrEdx;
|
||||
Ring0.Rdmsr(HWCR, out hwcrEax, out hwcrEdx);
|
||||
if (corePerformanceBoostSupport)
|
||||
Ring0.Wrmsr(HWCR, hwcrEax | (1 << 25), hwcrEdx);
|
||||
|
||||
uint ctlEax, ctlEdx;
|
||||
Ring0.Rdmsr(PERF_CTL_0, out ctlEax, out ctlEdx);
|
||||
uint ctrEax, ctrEdx;
|
||||
@@ -118,6 +128,10 @@ namespace OpenHardwareMonitor.Hardware.CPU {
|
||||
Ring0.Wrmsr(PERF_CTL_0, ctlEax, ctlEdx);
|
||||
Ring0.Wrmsr(PERF_CTR_0, ctrEax, ctrEdx);
|
||||
|
||||
// restore core performance boost
|
||||
if (corePerformanceBoostSupport)
|
||||
Ring0.Wrmsr(HWCR, hwcrEax, hwcrEdx);
|
||||
|
||||
// restore the thread affinity.
|
||||
ThreadAffinity.Set(mask);
|
||||
|
||||
@@ -178,10 +192,11 @@ namespace OpenHardwareMonitor.Hardware.CPU {
|
||||
long timeEnd = timeBegin + ticks;
|
||||
while (Stopwatch.GetTimestamp() < timeBegin) { }
|
||||
Ring0.Rdmsr(PERF_CTR_0, out lsbBegin, out msbBegin);
|
||||
|
||||
while (Stopwatch.GetTimestamp() < timeEnd) { }
|
||||
Ring0.Rdmsr(PERF_CTR_0, out lsbEnd, out msbEnd);
|
||||
|
||||
Ring0.Rdmsr(COFVID_STATUS, out eax, out edx);
|
||||
|
||||
double coreMultiplier;
|
||||
if (family == 0x14) {
|
||||
uint divisorIdMSD = (eax >> 4) & 0x1F;
|
||||
@@ -206,11 +221,13 @@ namespace OpenHardwareMonitor.Hardware.CPU {
|
||||
(timeEnd - timeBegin);
|
||||
|
||||
double busFrequency = coreFrequency / coreMultiplier;
|
||||
|
||||
return 0.25 * Math.Round(4 * TimeStampCounterFrequency / busFrequency);
|
||||
}
|
||||
|
||||
protected override uint[] GetMSRs() {
|
||||
return new uint[] { PERF_CTL_0, PERF_CTR_0, P_STATE_0, COFVID_STATUS };
|
||||
return new uint[] { PERF_CTL_0, PERF_CTR_0, HWCR, P_STATE_0,
|
||||
COFVID_STATUS };
|
||||
}
|
||||
|
||||
public override string GetReport() {
|
||||
|
||||
+48
-17
@@ -60,10 +60,12 @@ namespace OpenHardwareMonitor.Hardware.CPU {
|
||||
private readonly bool hasTimeStampCounter;
|
||||
private readonly bool isInvariantTimeStampCounter;
|
||||
private readonly double estimatedTimeStampCounterFrequency;
|
||||
private readonly double estimatedTimeStampCounterFrequencyError;
|
||||
|
||||
private ulong lastTimeStampCount;
|
||||
private long lastTime;
|
||||
private double timeStampCounterFrequency;
|
||||
private double timeStampCounterFrequency;
|
||||
|
||||
|
||||
private readonly Vendor vendor;
|
||||
|
||||
@@ -132,9 +134,10 @@ namespace OpenHardwareMonitor.Hardware.CPU {
|
||||
|
||||
if (hasTimeStampCounter) {
|
||||
ulong mask = ThreadAffinity.Set(1UL << cpuid[0][0].Thread);
|
||||
|
||||
estimatedTimeStampCounterFrequency =
|
||||
EstimateTimeStampCounterFrequency();
|
||||
|
||||
EstimateTimeStampCounterFrequency(
|
||||
out estimatedTimeStampCounterFrequency,
|
||||
out estimatedTimeStampCounterFrequencyError);
|
||||
|
||||
ThreadAffinity.Set(mask);
|
||||
} else {
|
||||
@@ -157,34 +160,55 @@ namespace OpenHardwareMonitor.Hardware.CPU {
|
||||
processorIndex.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
private static double EstimateTimeStampCounterFrequency() {
|
||||
private void EstimateTimeStampCounterFrequency(out double frequency,
|
||||
out double error)
|
||||
{
|
||||
double f, e;
|
||||
|
||||
// preload the function
|
||||
EstimateTimeStampCounterFrequency(0);
|
||||
EstimateTimeStampCounterFrequency(0);
|
||||
EstimateTimeStampCounterFrequency(0, out f, out e);
|
||||
EstimateTimeStampCounterFrequency(0, out f, out e);
|
||||
|
||||
// estimate the frequency in MHz
|
||||
List<double> estimatedFrequency = new List<double>(3);
|
||||
for (int i = 0; i < 3; i++)
|
||||
estimatedFrequency.Add(1e-6 * EstimateTimeStampCounterFrequency(0.025));
|
||||
|
||||
estimatedFrequency.Sort();
|
||||
return estimatedFrequency[1];
|
||||
// estimate the frequency
|
||||
error = double.MaxValue;
|
||||
frequency = 0;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
EstimateTimeStampCounterFrequency(0.025, out f, out e);
|
||||
if (e < error) {
|
||||
error = e;
|
||||
frequency = f;
|
||||
}
|
||||
|
||||
if (error < 1e-4)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static double EstimateTimeStampCounterFrequency(double timeWindow) {
|
||||
private void EstimateTimeStampCounterFrequency(double timeWindow,
|
||||
out double frequency, out double error)
|
||||
{
|
||||
long ticks = (long)(timeWindow * Stopwatch.Frequency);
|
||||
ulong countBegin, countEnd;
|
||||
|
||||
long timeBegin = Stopwatch.GetTimestamp() +
|
||||
(long)Math.Ceiling(0.001 * ticks);
|
||||
long timeEnd = timeBegin + ticks;
|
||||
|
||||
while (Stopwatch.GetTimestamp() < timeBegin) { }
|
||||
countBegin = Opcode.Rdtsc();
|
||||
long afterBegin = Stopwatch.GetTimestamp();
|
||||
|
||||
while (Stopwatch.GetTimestamp() < timeEnd) { }
|
||||
countEnd = Opcode.Rdtsc();
|
||||
long afterEnd = Stopwatch.GetTimestamp();
|
||||
|
||||
return (((double)(countEnd - countBegin)) * Stopwatch.Frequency) /
|
||||
(timeEnd - timeBegin);
|
||||
double delta = (timeEnd - timeBegin);
|
||||
frequency = 1e-6 *
|
||||
(((double)(countEnd - countBegin)) * Stopwatch.Frequency) / delta;
|
||||
|
||||
double beginError = (afterBegin - timeBegin) / delta;
|
||||
double endError = (afterEnd - timeEnd) / delta;
|
||||
error = beginError + endError;
|
||||
}
|
||||
|
||||
|
||||
@@ -224,6 +248,13 @@ namespace OpenHardwareMonitor.Hardware.CPU {
|
||||
"Timer Frequency: {0} MHz", Stopwatch.Frequency * 1e-6));
|
||||
r.AppendLine("Time Stamp Counter: " + (hasTimeStampCounter ? (
|
||||
isInvariantTimeStampCounter ? "Invariant" : "Not Invariant") : "None"));
|
||||
r.AppendLine(string.Format(CultureInfo.InvariantCulture,
|
||||
"Estimated Time Stamp Counter Frequency: {0} MHz",
|
||||
Math.Round(estimatedTimeStampCounterFrequency * 100) * 0.01));
|
||||
r.AppendLine(string.Format(CultureInfo.InvariantCulture,
|
||||
"Estimated Time Stamp Counter Frequency Error: {0} Mhz",
|
||||
Math.Round(estimatedTimeStampCounterFrequency *
|
||||
estimatedTimeStampCounterFrequencyError * 1e5) * 1e-5));
|
||||
r.AppendLine(string.Format(CultureInfo.InvariantCulture,
|
||||
"Time Stamp Counter Frequency: {0} MHz",
|
||||
Math.Round(timeStampCounterFrequency * 100) * 0.01));
|
||||
|
||||
+24
-1
@@ -66,7 +66,9 @@ namespace OpenHardwareMonitor.Hardware {
|
||||
IOCTL_OLS_READ_PCI_CONFIG = new IOControlCode(OLS_TYPE, 0x851,
|
||||
IOControlCode.Access.Read),
|
||||
IOCTL_OLS_WRITE_PCI_CONFIG = new IOControlCode(OLS_TYPE, 0x852,
|
||||
IOControlCode.Access.Write);
|
||||
IOControlCode.Access.Write),
|
||||
IOCTL_OLS_READ_MEMORY = new IOControlCode(OLS_TYPE, 0x841,
|
||||
IOControlCode.Access.Read);
|
||||
|
||||
private static bool ExtractDriver(string fileName) {
|
||||
string resourceName = "OpenHardwareMonitor.Hardware." +
|
||||
@@ -310,5 +312,26 @@ namespace OpenHardwareMonitor.Hardware {
|
||||
|
||||
return driver.DeviceIOControl(IOCTL_OLS_WRITE_PCI_CONFIG, input);
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
private struct ReadMemoryInput {
|
||||
public ulong address;
|
||||
public uint unitSize;
|
||||
public uint count;
|
||||
}
|
||||
|
||||
public static bool ReadMemory<T>(ulong address, ref T buffer) {
|
||||
if (driver == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ReadMemoryInput input = new ReadMemoryInput();
|
||||
input.address = address;
|
||||
input.unitSize = 1;
|
||||
input.count = (uint)Marshal.SizeOf(buffer);
|
||||
|
||||
return driver.DeviceIOControl(IOCTL_OLS_READ_MEMORY, input,
|
||||
ref buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,5 +37,5 @@
|
||||
|
||||
using System.Reflection;
|
||||
|
||||
[assembly: AssemblyVersion("0.3.0.3")]
|
||||
[assembly: AssemblyInformationalVersion("0.3.0.3 Alpha")]
|
||||
[assembly: AssemblyVersion("0.3.0.5")]
|
||||
[assembly: AssemblyInformationalVersion("0.3.0.5 Alpha")]
|
||||
Reference in New Issue
Block a user