Hardware/CPU/GenericCPU.cs
changeset 236 763675f19ff4
parent 222 ba64bb91ebe4
child 238 bddc6e01840a
     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  }