# HG changeset patch # User moel.mich # Date 1304892613 0 # Node ID 6bce967ba1b5cab95f73812274488dde550f74f4 # Parent 803f98bf1418c048c170c957061fae2e5ec7e577 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. diff -r 803f98bf1418 -r 6bce967ba1b5 Hardware/CPU/AMD10CPU.cs --- a/Hardware/CPU/AMD10CPU.cs Tue May 03 18:20:06 2011 +0000 +++ b/Hardware/CPU/AMD10CPU.cs Sun May 08 22:10:13 2011 +0000 @@ -54,6 +54,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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); - Ring0.Rdmsr(COFVID_STATUS, out eax, out edx); double coreMultiplier; if (family == 0x14) { uint divisorIdMSD = (eax >> 4) & 0x1F; @@ -206,11 +221,13 @@ (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() { diff -r 803f98bf1418 -r 6bce967ba1b5 Hardware/CPU/GenericCPU.cs --- a/Hardware/CPU/GenericCPU.cs Tue May 03 18:20:06 2011 +0000 +++ b/Hardware/CPU/GenericCPU.cs Sun May 08 22:10:13 2011 +0000 @@ -60,10 +60,12 @@ 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 @@ 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 @@ 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 estimatedFrequency = new List(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; } @@ -225,6 +249,13 @@ 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)); r.AppendLine(); diff -r 803f98bf1418 -r 6bce967ba1b5 Hardware/Ring0.cs --- a/Hardware/Ring0.cs Tue May 03 18:20:06 2011 +0000 +++ b/Hardware/Ring0.cs Sun May 08 22:10:13 2011 +0000 @@ -66,7 +66,9 @@ 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 @@ 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(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); + } } } diff -r 803f98bf1418 -r 6bce967ba1b5 Properties/AssemblyVersion.cs --- a/Properties/AssemblyVersion.cs Tue May 03 18:20:06 2011 +0000 +++ b/Properties/AssemblyVersion.cs Sun May 08 22:10:13 2011 +0000 @@ -37,5 +37,5 @@ using System.Reflection; -[assembly: AssemblyVersion("0.3.0.3")] -[assembly: AssemblyInformationalVersion("0.3.0.3 Alpha")] \ No newline at end of file +[assembly: AssemblyVersion("0.3.0.5")] +[assembly: AssemblyInformationalVersion("0.3.0.5 Alpha")] \ No newline at end of file