# HG changeset patch # User moel.mich # Date 1285865469 0 # Node ID 958e9fe8afdf92f4dd40b58a02ea39bc3e1fa413 # Parent 50de2faf3336ebf106c5445d75a6047de532cc1d Improved the implementation for the AMD 10h family CPU clock speeds. diff -r 50de2faf3336 -r 958e9fe8afdf Hardware/CPU/AMD0FCPU.cs --- a/Hardware/CPU/AMD0FCPU.cs Mon Sep 27 23:48:41 2010 +0000 +++ b/Hardware/CPU/AMD0FCPU.cs Thu Sep 30 16:51:09 2010 +0000 @@ -92,7 +92,7 @@ for (int i = 0; i < coreClocks.Length; i++) { coreClocks[i] = new Sensor(CoreString(i), i + 1, SensorType.Clock, this, settings); - if (hasTSC) + if (HasTimeStampCounter) ActivateSensor(coreClocks[i]); } @@ -138,7 +138,7 @@ } } - if (hasTSC) { + if (HasTimeStampCounter) { double newBusClock = 0; for (int i = 0; i < coreClocks.Length; i++) { @@ -151,11 +151,12 @@ // 8-13 hold StartFID, we don't use that here. double curMP = 0.5 * ((eax & 0x3F) + 8); double maxMP = 0.5 * ((eax >> 16 & 0x3F) + 8); - coreClocks[i].Value = (float)(curMP * MaxClock / maxMP); - newBusClock = (float)(MaxClock / maxMP); + coreClocks[i].Value = + (float)(curMP * TimeStampCounterFrequency / maxMP); + newBusClock = (float)(TimeStampCounterFrequency / maxMP); } else { // Fail-safe value - if the code above fails, we'll use this instead - coreClocks[i].Value = (float)MaxClock; + coreClocks[i].Value = (float)TimeStampCounterFrequency; } } diff -r 50de2faf3336 -r 958e9fe8afdf Hardware/CPU/AMD10CPU.cs --- a/Hardware/CPU/AMD10CPU.cs Mon Sep 27 23:48:41 2010 +0000 +++ b/Hardware/CPU/AMD10CPU.cs Thu Sep 30 16:51:09 2010 +0000 @@ -36,7 +36,10 @@ */ using System; +using System.Collections.Generic; +using System.Diagnostics; using System.Globalization; +using System.Runtime.InteropServices; using System.Text; using System.Threading; @@ -47,16 +50,22 @@ private readonly Sensor coreTemperature; private readonly Sensor[] coreClocks; private readonly Sensor busClock; - + + private const uint PERF_CTL_0 = 0xC0010000; + private const uint PERF_CTR_0 = 0xC0010004; + private const uint P_STATE_0 = 0xC0010064; private const uint COFVID_STATUS = 0xC0010071; - private const uint P_STATE_0 = 0xC0010064; private const byte MISCELLANEOUS_CONTROL_FUNCTION = 3; private const ushort MISCELLANEOUS_CONTROL_DEVICE_ID = 0x1203; private const uint REPORTED_TEMPERATURE_CONTROL_REGISTER = 0xA4; - + private readonly uint miscellaneousControlAddress; + private double timeStampCounterMultiplier; + + private StringBuilder debug = new StringBuilder(); + public AMD10CPU(int processorIndex, CPUID[][] cpuid, ISettings settings) : base(processorIndex, cpuid, settings) { @@ -76,15 +85,87 @@ for (int i = 0; i < coreClocks.Length; i++) { coreClocks[i] = new Sensor(CoreString(i), i + 1, SensorType.Clock, this, settings); - if (hasTSC) + if (HasTimeStampCounter) ActivateSensor(coreClocks[i]); } + // set affinity to the first thread for all frequency estimations + IntPtr thread = NativeMethods.GetCurrentThread(); + UIntPtr mask = NativeMethods.SetThreadAffinityMask(thread, + (UIntPtr)(1L << cpuid[0][0].Thread)); + + uint ctlEax, ctlEdx; + WinRing0.Rdmsr(PERF_CTL_0, out ctlEax, out ctlEdx); + uint ctrEax, ctrEdx; + WinRing0.Rdmsr(PERF_CTR_0, out ctrEax, out ctrEdx); + + timeStampCounterMultiplier = estimateTimeStampCounterMultiplier(); + + // restore the performance counter registers + WinRing0.Wrmsr(PERF_CTL_0, ctlEax, ctlEdx); + WinRing0.Wrmsr(PERF_CTR_0, ctrEax, ctrEdx); + + // restore the thread affinity. + NativeMethods.SetThreadAffinityMask(thread, mask); + Update(); } + private double estimateTimeStampCounterMultiplier() { + // preload the function + estimateTimeStampCounterMultiplier(0); + estimateTimeStampCounterMultiplier(0); + + // estimate the multiplier + List estimate = new List(3); + for (int i = 0; i < 3; i++) + estimate.Add(estimateTimeStampCounterMultiplier(0.025)); + estimate.Sort(); + return estimate[1]; + } + + private double estimateTimeStampCounterMultiplier(double timeWindow) { + uint eax, edx; + + // select event "076h CPU Clocks not Halted" and enable the counter + WinRing0.Wrmsr(PERF_CTL_0, + (1 << 22) | // enable performance counter + (1 << 17) | // count events in user mode + (1 << 16) | // count events in operating-system mode + 0x76, 0x00000000); + + // set the counter to 0 + WinRing0.Wrmsr(PERF_CTR_0, 0, 0); + + long ticks = (long)(timeWindow * Stopwatch.Frequency); + uint lsbBegin, msbBegin, lsbEnd, msbEnd; + + long timeBegin = Stopwatch.GetTimestamp() + + (long)Math.Ceiling(0.001 * ticks); + long timeEnd = timeBegin + ticks; + while (Stopwatch.GetTimestamp() < timeBegin) { } + WinRing0.Rdmsr(PERF_CTR_0, out lsbBegin, out msbBegin); + while (Stopwatch.GetTimestamp() < timeEnd) { } + WinRing0.Rdmsr(PERF_CTR_0, out lsbEnd, out msbEnd); + + WinRing0.Rdmsr(COFVID_STATUS, out eax, out edx); + uint cpuDid = (eax >> 6) & 7; + uint cpuFid = eax & 0x1F; + double coreMultiplier = MultiplierFromIDs(cpuDid, cpuFid); + + ulong countBegin = ((ulong)msbBegin << 32) | lsbBegin; + ulong countEnd = ((ulong)msbEnd << 32) | lsbEnd; + + double coreFrequency = 1e-6 * + (((double)(countEnd - countBegin)) * Stopwatch.Frequency) / + (timeEnd - timeBegin); + + double busFrequency = coreFrequency / coreMultiplier; + return 0.5 * Math.Round(2 * TimeStampCounterFrequency / busFrequency); + } + protected override uint[] GetMSRs() { - return new uint[] { P_STATE_0, COFVID_STATUS }; + return new uint[] { PERF_CTL_0, PERF_CTR_0, P_STATE_0, COFVID_STATUS }; } public override string GetReport() { @@ -94,12 +175,18 @@ r.Append("Miscellaneous Control Address: 0x"); r.AppendLine((miscellaneousControlAddress).ToString("X", CultureInfo.InvariantCulture)); + r.Append("Time Stamp Counter Multiplier: "); + r.AppendLine(timeStampCounterMultiplier.ToString( + CultureInfo.InvariantCulture)); + r.AppendLine(); + + r.Append(debug); r.AppendLine(); return r.ToString(); } - private double MultiplierFromIDs(uint divisorID, uint frequencyID) { + private static double MultiplierFromIDs(uint divisorID, uint frequencyID) { return 0.5 * (frequencyID + 0x10) / (1 << (int)divisorID); } @@ -118,35 +205,29 @@ } } - if (hasTSC) { + if (HasTimeStampCounter) { double newBusClock = 0; for (int i = 0; i < coreClocks.Length; i++) { Thread.Sleep(1); uint curEax, curEdx; - uint maxEax, maxEdx; if (WinRing0.RdmsrTx(COFVID_STATUS, out curEax, out curEdx, - (UIntPtr)(1L << cpuid[i][0].Thread)) && - WinRing0.RdmsrTx(P_STATE_0, out maxEax, out maxEdx, (UIntPtr)(1L << cpuid[i][0].Thread))) { // 8:6 CpuDid: current core divisor ID // 5:0 CpuFid: current core frequency ID - uint curCpuDid = (curEax >> 6) & 7; - uint curCpuFid = curEax & 0x1F; - double multiplier = MultiplierFromIDs(curCpuDid, curCpuFid); + uint cpuDid = (curEax >> 6) & 7; + uint cpuFid = curEax & 0x1F; + double multiplier = MultiplierFromIDs(cpuDid, cpuFid); - // we assume that the max multiplier (used for the TSC) - // can be found in the P_STATE_0 MSR - uint maxCpuDid = (maxEax >> 6) & 7; - uint maxCpuFid = maxEax & 0x1F; - double maxMultiplier = MultiplierFromIDs(maxCpuDid, maxCpuFid); - - coreClocks[i].Value = (float)(multiplier * MaxClock / maxMultiplier); - newBusClock = (float)(MaxClock / maxMultiplier); + coreClocks[i].Value = + (float)(multiplier * TimeStampCounterFrequency / + timeStampCounterMultiplier); + newBusClock = + (float)(TimeStampCounterFrequency / timeStampCounterMultiplier); } else { - coreClocks[i].Value = (float)MaxClock; + coreClocks[i].Value = (float)TimeStampCounterFrequency; } } @@ -155,6 +236,17 @@ ActivateSensor(this.busClock); } } - } + } + + private static class NativeMethods { + private const string KERNEL = "kernel32.dll"; + + [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)] + public static extern UIntPtr + SetThreadAffinityMask(IntPtr handle, UIntPtr mask); + + [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)] + public static extern IntPtr GetCurrentThread(); + } } } diff -r 50de2faf3336 -r 958e9fe8afdf Hardware/CPU/GenericCPU.cs --- a/Hardware/CPU/GenericCPU.cs Mon Sep 27 23:48:41 2010 +0000 +++ b/Hardware/CPU/GenericCPU.cs Thu Sep 30 16:51:09 2010 +0000 @@ -55,13 +55,13 @@ protected readonly int coreCount; protected readonly string name; - protected readonly bool hasTSC; - protected readonly bool invariantTSC; - private readonly double estimatedMaxClock; + private readonly bool hasTimeStampCounter; + private readonly bool isInvariantTimeStampCounter; + private readonly double estimatedTimeStampCounterFrequency; private ulong lastTimeStampCount; private long lastTime; - private double maxClock; + private double timeStampCounterFrequency; private readonly Vendor vendor; @@ -89,19 +89,19 @@ this.coreCount = cpuid.Length; this.name = cpuid[0][0].Name; - // check if processor has TSC + // check if processor has a TSC if (cpuid[0][0].Data.GetLength(0) > 1 && (cpuid[0][0].Data[1, 3] & 0x10) != 0) - hasTSC = true; + hasTimeStampCounter = true; else - hasTSC = false; + hasTimeStampCounter = false; - // check if processor supports invariant TSC + // check if processor supports an invariant TSC if (cpuid[0][0].ExtData.GetLength(0) > 7 && (cpuid[0][0].ExtData[7, 3] & 0x100) != 0) - invariantTSC = true; + isInvariantTimeStampCounter = true; else - invariantTSC = false; + isInvariantTimeStampCounter = false; if (coreCount > 1) totalLoad = new Sensor("CPU Total", 0, SensorType.Load, this, settings); @@ -119,30 +119,30 @@ ActivateSensor(totalLoad); } - if (hasTSC) - estimatedMaxClock = EstimateMaxClock(); + if (hasTimeStampCounter) + estimatedTimeStampCounterFrequency = EstimateTimeStampCounterFrequency(); else - estimatedMaxClock = 0; - maxClock = estimatedMaxClock; + estimatedTimeStampCounterFrequency = 0; + timeStampCounterFrequency = estimatedTimeStampCounterFrequency; lastTimeStampCount = 0; lastTime = 0; } - private static double EstimateMaxClock() { + private static double EstimateTimeStampCounterFrequency() { // preload the function - EstimateMaxClock(0); - EstimateMaxClock(0); + EstimateTimeStampCounterFrequency(0); + EstimateTimeStampCounterFrequency(0); - // estimate the max clock in MHz - List estimatedMaxClocks = new List(3); + // estimate the frequency in MHz + List estimatedFrequency = new List(3); for (int i = 0; i < 3; i++) - estimatedMaxClocks.Add(1e-6 * EstimateMaxClock(0.025)); - estimatedMaxClocks.Sort(); - return estimatedMaxClocks[1]; + estimatedFrequency.Add(1e-6 * EstimateTimeStampCounterFrequency(0.025)); + estimatedFrequency.Sort(); + return estimatedFrequency[1]; } - private static double EstimateMaxClock(double timeWindow) { + private static double EstimateTimeStampCounterFrequency(double timeWindow) { long ticks = (long)(timeWindow * Stopwatch.Frequency); uint lsbBegin, msbBegin, lsbEnd, msbEnd; @@ -195,12 +195,13 @@ Environment.NewLine); r.AppendFormat("Threads per Core: {0}{1}", cpuid[0].Length, Environment.NewLine); - r.AppendLine("TSC: " + - (hasTSC ? (invariantTSC ? "Invariant" : "Not Invariant") : "None")); r.AppendLine(string.Format(CultureInfo.InvariantCulture, "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, - "Max Clock: {0} MHz", Math.Round(maxClock * 100) * 0.01)); + "Time Stamp Counter Frequency: {0} MHz", + Math.Round(timeStampCounterFrequency * 100) * 0.01)); r.AppendLine(); uint[] msrArray = GetMSRs(); @@ -239,22 +240,27 @@ get { return HardwareType.CPU; } } - protected double MaxClock { - get { return maxClock; } + public bool HasTimeStampCounter { + get { return hasTimeStampCounter; } + } + + public double TimeStampCounterFrequency { + get { return timeStampCounterFrequency; } } public override void Update() { - if (hasTSC) { + if (hasTimeStampCounter) { uint lsb, msb; WinRing0.RdtscTx(out lsb, out msb, (UIntPtr)1); long time = Stopwatch.GetTimestamp(); ulong timeStampCount = ((ulong)msb << 32) | lsb; double delta = ((double)(time - lastTime)) / Stopwatch.Frequency; if (delta > 0.5) { - if (invariantTSC) - maxClock = (timeStampCount - lastTimeStampCount) / (1e6 * delta); + if (isInvariantTimeStampCounter) + timeStampCounterFrequency = + (timeStampCount - lastTimeStampCount) / (1e6 * delta); else - maxClock = estimatedMaxClock; + timeStampCounterFrequency = estimatedTimeStampCounterFrequency; lastTimeStampCount = timeStampCount; lastTime = time; diff -r 50de2faf3336 -r 958e9fe8afdf Hardware/CPU/IntelCPU.cs --- a/Hardware/CPU/IntelCPU.cs Mon Sep 27 23:48:41 2010 +0000 +++ b/Hardware/CPU/IntelCPU.cs Thu Sep 30 16:51:09 2010 +0000 @@ -145,7 +145,7 @@ for (int i = 0; i < coreClocks.Length; i++) { coreClocks[i] = new Sensor(CoreString(i), i + 1, SensorType.Clock, this, settings); - if (hasTSC) + if (HasTimeStampCounter) ActivateSensor(coreClocks[i]); } @@ -182,7 +182,7 @@ } } - if (hasTSC) { + if (HasTimeStampCounter) { double newBusClock = 0; uint eax, edx; for (int i = 0; i < coreClocks.Length; i++) { @@ -191,9 +191,10 @@ (UIntPtr)(1L << cpuid[i][0].Thread))) { if (maxNehalemMultiplier > 0) { // Core i3, i5, i7 uint nehalemMultiplier = eax & 0xff; - coreClocks[i].Value = - (float)(nehalemMultiplier * MaxClock / maxNehalemMultiplier); - newBusClock = (float)(MaxClock / maxNehalemMultiplier); + coreClocks[i].Value =(float)(nehalemMultiplier * + TimeStampCounterFrequency / maxNehalemMultiplier); + newBusClock = + (float)(TimeStampCounterFrequency / maxNehalemMultiplier); } else { // Core 2 uint multiplier = (eax >> 8) & 0x1f; uint maxMultiplier = (edx >> 8) & 0x1f; @@ -201,13 +202,15 @@ uint factor = (multiplier << 1) | ((eax >> 14) & 1); uint maxFactor = (maxMultiplier << 1) | ((edx >> 14) & 1); if (maxFactor > 0) { - coreClocks[i].Value = (float)(factor * MaxClock / maxFactor); - newBusClock = (float)(2 * MaxClock / maxFactor); + coreClocks[i].Value = + (float)(factor * TimeStampCounterFrequency / maxFactor); + newBusClock = + (float)(2 * TimeStampCounterFrequency / maxFactor); } } } else { // Intel Pentium 4 - // if IA32_PERF_STATUS is not available, assume maxClock - coreClocks[i].Value = (float)MaxClock; + // if IA32_PERF_STATUS is not available, assume TSC frequency + coreClocks[i].Value = (float)TimeStampCounterFrequency; } } if (newBusClock > 0) { diff -r 50de2faf3336 -r 958e9fe8afdf Hardware/WinRing0.cs --- a/Hardware/WinRing0.cs Mon Sep 27 23:48:41 2010 +0000 +++ b/Hardware/WinRing0.cs Thu Sep 30 16:51:09 2010 +0000 @@ -90,10 +90,13 @@ public delegate bool ReadPciConfigDwordExDelegate(uint pciAddress, uint regAddress, out uint value); public delegate bool WritePciConfigDwordExDelegate(uint pciAddress, - uint regAddress, uint value); + uint regAddress, uint value); + public delegate bool RdtscDelegate(out uint eax, out uint edx); public delegate bool RdtscTxDelegate(out uint eax, out uint edx, + UIntPtr threadAffinityMask); + public delegate bool WrmsrDelegate(uint index, uint eax, uint edx); + public delegate bool WrmsrTxDelegate(uint index, uint eax, uint edx, UIntPtr threadAffinityMask); - public delegate bool RdtscDelegate(out uint eax, out uint edx); private static readonly InitializeOlsDelegate InitializeOls = CreateDelegate("InitializeOls"); @@ -116,10 +119,14 @@ CreateDelegate("ReadPciConfigDwordEx"); public static readonly WritePciConfigDwordExDelegate WritePciConfigDwordEx = CreateDelegate("WritePciConfigDwordEx"); - public static readonly RdtscTxDelegate RdtscTx = - CreateDelegate("RdtscTx"); public static readonly RdtscDelegate Rdtsc = CreateDelegate("Rdtsc"); + public static readonly RdtscTxDelegate RdtscTx = + CreateDelegate("RdtscTx"); + public static readonly WrmsrDelegate Wrmsr = + CreateDelegate("Wrmsr"); + public static readonly WrmsrTxDelegate WrmsrTx = + CreateDelegate("WrmsrTx"); private static T CreateDelegate(string entryPoint) where T : class { DllImportAttribute attribute = new DllImportAttribute(GetDllName()); diff -r 50de2faf3336 -r 958e9fe8afdf Properties/AssemblyVersion.cs --- a/Properties/AssemblyVersion.cs Mon Sep 27 23:48:41 2010 +0000 +++ b/Properties/AssemblyVersion.cs Thu Sep 30 16:51:09 2010 +0000 @@ -37,5 +37,5 @@ using System.Reflection; -[assembly: AssemblyVersion("0.1.37.17")] -[assembly: AssemblyInformationalVersion("0.1.37.17 Alpha")] \ No newline at end of file +[assembly: AssemblyVersion("0.1.37.23")] +[assembly: AssemblyInformationalVersion("0.1.37.23 Alpha")] \ No newline at end of file