1.1 --- a/Hardware/CPU/GenericCPU.cs Mon Oct 18 07:18:14 2010 +0000
1.2 +++ b/Hardware/CPU/GenericCPU.cs Sun Oct 31 22:08:47 2010 +0000
1.3 @@ -39,6 +39,7 @@
1.4 using System.Collections.Generic;
1.5 using System.Diagnostics;
1.6 using System.Globalization;
1.7 +using System.Runtime.InteropServices;
1.8 using System.Text;
1.9 using System.Threading;
1.10
1.11 @@ -55,6 +56,8 @@
1.12 protected readonly int coreCount;
1.13 protected readonly string name;
1.14
1.15 + private readonly bool hasModelSpecificRegisters;
1.16 +
1.17 private readonly bool hasTimeStampCounter;
1.18 private readonly bool isInvariantTimeStampCounter;
1.19 private readonly double estimatedTimeStampCounterFrequency;
1.20 @@ -87,7 +90,14 @@
1.21
1.22 this.processorIndex = processorIndex;
1.23 this.coreCount = cpuid.Length;
1.24 - this.name = cpuid[0][0].Name;
1.25 + this.name = cpuid[0][0].Name;
1.26 +
1.27 + // check if processor has MSRs
1.28 + if (cpuid[0][0].Data.GetLength(0) > 1
1.29 + && (cpuid[0][0].Data[1, 3] & 0x20) != 0)
1.30 + hasModelSpecificRegisters = true;
1.31 + else
1.32 + hasModelSpecificRegisters = false;
1.33
1.34 // check if processor has a TSC
1.35 if (cpuid[0][0].Data.GetLength(0) > 1
1.36 @@ -144,28 +154,26 @@
1.37
1.38 private static double EstimateTimeStampCounterFrequency(double timeWindow) {
1.39 long ticks = (long)(timeWindow * Stopwatch.Frequency);
1.40 - uint lsbBegin, msbBegin, lsbEnd, msbEnd;
1.41 + ulong countBegin, countEnd;
1.42
1.43 Thread.BeginThreadAffinity();
1.44 long timeBegin = Stopwatch.GetTimestamp() +
1.45 (long)Math.Ceiling(0.001 * ticks);
1.46 long timeEnd = timeBegin + ticks;
1.47 while (Stopwatch.GetTimestamp() < timeBegin) { }
1.48 - WinRing0.Rdtsc(out lsbBegin, out msbBegin);
1.49 + countBegin = Opcode.Rdtsc();
1.50 while (Stopwatch.GetTimestamp() < timeEnd) { }
1.51 - WinRing0.Rdtsc(out lsbEnd, out msbEnd);
1.52 + countEnd = Opcode.Rdtsc();
1.53 Thread.EndThreadAffinity();
1.54
1.55 - ulong countBegin = ((ulong)msbBegin << 32) | lsbBegin;
1.56 - ulong countEnd = ((ulong)msbEnd << 32) | lsbEnd;
1.57 -
1.58 return (((double)(countEnd - countBegin)) * Stopwatch.Frequency) /
1.59 (timeEnd - timeBegin);
1.60 }
1.61
1.62 +
1.63 private static void AppendMSRData(StringBuilder r, uint msr, int thread) {
1.64 uint eax, edx;
1.65 - if (WinRing0.RdmsrTx(msr, out eax, out edx, (UIntPtr)(1L << thread))) {
1.66 + if (Ring0.RdmsrTx(msr, out eax, out edx, (UIntPtr)(1L << thread))) {
1.67 r.Append(" ");
1.68 r.Append((msr).ToString("X8", CultureInfo.InvariantCulture));
1.69 r.Append(" ");
1.70 @@ -240,6 +248,10 @@
1.71 get { return HardwareType.CPU; }
1.72 }
1.73
1.74 + public bool HasModelSpecificRegisters {
1.75 + get { return hasModelSpecificRegisters; }
1.76 + }
1.77 +
1.78 public bool HasTimeStampCounter {
1.79 get { return hasTimeStampCounter; }
1.80 }
1.81 @@ -250,14 +262,20 @@
1.82
1.83 public override void Update() {
1.84 if (hasTimeStampCounter && isInvariantTimeStampCounter) {
1.85 - uint lsb, msb;
1.86 +
1.87 + // make sure always the same thread is used
1.88 + IntPtr thread = NativeMethods.GetCurrentThread();
1.89 + UIntPtr mask = NativeMethods.SetThreadAffinityMask(thread,
1.90 + (UIntPtr)(1L << cpuid[0][0].Thread));
1.91
1.92 // read time before and after getting the TSC to estimate the error
1.93 long firstTime = Stopwatch.GetTimestamp();
1.94 - WinRing0.RdtscTx(out lsb, out msb, (UIntPtr)1);
1.95 + ulong timeStampCount = Opcode.Rdtsc();
1.96 long time = Stopwatch.GetTimestamp();
1.97
1.98 - ulong timeStampCount = ((ulong)msb << 32) | lsb;
1.99 + // restore the thread affinity mask
1.100 + NativeMethods.SetThreadAffinityMask(thread, mask);
1.101 +
1.102 double delta = ((double)(time - lastTime)) / Stopwatch.Frequency;
1.103 double error = ((double)(time - firstTime)) / Stopwatch.Frequency;
1.104
1.105 @@ -286,5 +304,16 @@
1.106 totalLoad.Value = cpuLoad.GetTotalLoad();
1.107 }
1.108 }
1.109 +
1.110 + private static class NativeMethods {
1.111 + private const string KERNEL = "kernel32.dll";
1.112 +
1.113 + [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
1.114 + public static extern UIntPtr
1.115 + SetThreadAffinityMask(IntPtr handle, UIntPtr mask);
1.116 +
1.117 + [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
1.118 + public static extern IntPtr GetCurrentThread();
1.119 + }
1.120 }
1.121 }