diff --git a/Hardware/CPU/AMD10CPU.cs b/Hardware/CPU/AMD10CPU.cs index 9320641..2760fbd 100644 --- a/Hardware/CPU/AMD10CPU.cs +++ b/Hardware/CPU/AMD10CPU.cs @@ -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() { diff --git a/Hardware/CPU/GenericCPU.cs b/Hardware/CPU/GenericCPU.cs index f8765ff..65e7617 100644 --- a/Hardware/CPU/GenericCPU.cs +++ b/Hardware/CPU/GenericCPU.cs @@ -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 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; } @@ -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)); diff --git a/Hardware/Ring0.cs b/Hardware/Ring0.cs index 5c01f89..0755380 100644 --- a/Hardware/Ring0.cs +++ b/Hardware/Ring0.cs @@ -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(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 --git a/Properties/AssemblyVersion.cs b/Properties/AssemblyVersion.cs index 176ce12..e74f0ff 100644 --- a/Properties/AssemblyVersion.cs +++ b/Properties/AssemblyVersion.cs @@ -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