Improved the implementation for the AMD 10h family CPU clock speeds.
authormoel.mich
Thu, 30 Sep 2010 16:51:09 +0000
changeset 201958e9fe8afdf
parent 200 50de2faf3336
child 202 551243a66b32
Improved the implementation for the AMD 10h family CPU clock speeds.
Hardware/CPU/AMD0FCPU.cs
Hardware/CPU/AMD10CPU.cs
Hardware/CPU/GenericCPU.cs
Hardware/CPU/IntelCPU.cs
Hardware/WinRing0.cs
Properties/AssemblyVersion.cs
     1.1 --- a/Hardware/CPU/AMD0FCPU.cs	Mon Sep 27 23:48:41 2010 +0000
     1.2 +++ b/Hardware/CPU/AMD0FCPU.cs	Thu Sep 30 16:51:09 2010 +0000
     1.3 @@ -92,7 +92,7 @@
     1.4        for (int i = 0; i < coreClocks.Length; i++) {
     1.5          coreClocks[i] = new Sensor(CoreString(i), i + 1, SensorType.Clock,
     1.6            this, settings);
     1.7 -        if (hasTSC)
     1.8 +        if (HasTimeStampCounter)
     1.9            ActivateSensor(coreClocks[i]);
    1.10        }
    1.11  
    1.12 @@ -138,7 +138,7 @@
    1.13          }
    1.14        }
    1.15  
    1.16 -      if (hasTSC) {
    1.17 +      if (HasTimeStampCounter) {
    1.18          double newBusClock = 0;
    1.19  
    1.20          for (int i = 0; i < coreClocks.Length; i++) {
    1.21 @@ -151,11 +151,12 @@
    1.22              // 8-13 hold StartFID, we don't use that here.
    1.23              double curMP = 0.5 * ((eax & 0x3F) + 8);
    1.24              double maxMP = 0.5 * ((eax >> 16 & 0x3F) + 8);
    1.25 -            coreClocks[i].Value = (float)(curMP * MaxClock / maxMP);
    1.26 -            newBusClock = (float)(MaxClock / maxMP);
    1.27 +            coreClocks[i].Value = 
    1.28 +              (float)(curMP * TimeStampCounterFrequency / maxMP);
    1.29 +            newBusClock = (float)(TimeStampCounterFrequency / maxMP);
    1.30            } else {
    1.31              // Fail-safe value - if the code above fails, we'll use this instead
    1.32 -            coreClocks[i].Value = (float)MaxClock;
    1.33 +            coreClocks[i].Value = (float)TimeStampCounterFrequency;
    1.34            }
    1.35          }
    1.36  
     2.1 --- a/Hardware/CPU/AMD10CPU.cs	Mon Sep 27 23:48:41 2010 +0000
     2.2 +++ b/Hardware/CPU/AMD10CPU.cs	Thu Sep 30 16:51:09 2010 +0000
     2.3 @@ -36,7 +36,10 @@
     2.4  */
     2.5  
     2.6  using System;
     2.7 +using System.Collections.Generic;
     2.8 +using System.Diagnostics;
     2.9  using System.Globalization;
    2.10 +using System.Runtime.InteropServices;
    2.11  using System.Text;
    2.12  using System.Threading;
    2.13  
    2.14 @@ -47,16 +50,22 @@
    2.15      private readonly Sensor coreTemperature;
    2.16      private readonly Sensor[] coreClocks;
    2.17      private readonly Sensor busClock;
    2.18 -
    2.19 +      
    2.20 +    private const uint PERF_CTL_0 = 0xC0010000;
    2.21 +    private const uint PERF_CTR_0 = 0xC0010004;
    2.22 +    private const uint P_STATE_0 = 0xC0010064;
    2.23      private const uint COFVID_STATUS = 0xC0010071;
    2.24 -    private const uint P_STATE_0 = 0xC0010064;
    2.25  
    2.26      private const byte MISCELLANEOUS_CONTROL_FUNCTION = 3;
    2.27      private const ushort MISCELLANEOUS_CONTROL_DEVICE_ID = 0x1203;
    2.28      private const uint REPORTED_TEMPERATURE_CONTROL_REGISTER = 0xA4;
    2.29 -    
    2.30 +
    2.31      private readonly uint miscellaneousControlAddress;
    2.32  
    2.33 +    private double timeStampCounterMultiplier;
    2.34 +
    2.35 +    private StringBuilder debug = new StringBuilder();
    2.36 +
    2.37      public AMD10CPU(int processorIndex, CPUID[][] cpuid, ISettings settings)
    2.38        : base(processorIndex, cpuid, settings) 
    2.39      {            
    2.40 @@ -76,15 +85,87 @@
    2.41        for (int i = 0; i < coreClocks.Length; i++) {
    2.42          coreClocks[i] = new Sensor(CoreString(i), i + 1, SensorType.Clock,
    2.43            this, settings);
    2.44 -        if (hasTSC)
    2.45 +        if (HasTimeStampCounter)
    2.46            ActivateSensor(coreClocks[i]);
    2.47        }
    2.48  
    2.49 +      // set affinity to the first thread for all frequency estimations
    2.50 +      IntPtr thread = NativeMethods.GetCurrentThread();
    2.51 +      UIntPtr mask = NativeMethods.SetThreadAffinityMask(thread,
    2.52 +        (UIntPtr)(1L << cpuid[0][0].Thread));
    2.53 +
    2.54 +      uint ctlEax, ctlEdx;
    2.55 +      WinRing0.Rdmsr(PERF_CTL_0, out ctlEax, out ctlEdx);
    2.56 +      uint ctrEax, ctrEdx;
    2.57 +      WinRing0.Rdmsr(PERF_CTR_0, out ctrEax, out ctrEdx);
    2.58 +
    2.59 +      timeStampCounterMultiplier = estimateTimeStampCounterMultiplier();
    2.60 +
    2.61 +      // restore the performance counter registers
    2.62 +      WinRing0.Wrmsr(PERF_CTL_0, ctlEax, ctlEdx);
    2.63 +      WinRing0.Wrmsr(PERF_CTR_0, ctrEax, ctrEdx);
    2.64 +
    2.65 +      // restore the thread affinity.
    2.66 +      NativeMethods.SetThreadAffinityMask(thread, mask);
    2.67 +
    2.68        Update();                   
    2.69      }
    2.70  
    2.71 +    private double estimateTimeStampCounterMultiplier() {
    2.72 +      // preload the function
    2.73 +      estimateTimeStampCounterMultiplier(0);
    2.74 +      estimateTimeStampCounterMultiplier(0);
    2.75 +
    2.76 +      // estimate the multiplier
    2.77 +      List<double> estimate = new List<double>(3);
    2.78 +      for (int i = 0; i < 3; i++)
    2.79 +        estimate.Add(estimateTimeStampCounterMultiplier(0.025));
    2.80 +      estimate.Sort();
    2.81 +      return estimate[1];
    2.82 +    }
    2.83 +
    2.84 +    private double estimateTimeStampCounterMultiplier(double timeWindow) {
    2.85 +      uint eax, edx;
    2.86 +     
    2.87 +      // select event "076h CPU Clocks not Halted" and enable the counter
    2.88 +      WinRing0.Wrmsr(PERF_CTL_0,
    2.89 +        (1 << 22) | // enable performance counter
    2.90 +        (1 << 17) | // count events in user mode
    2.91 +        (1 << 16) | // count events in operating-system mode
    2.92 +        0x76, 0x00000000);
    2.93 +
    2.94 +      // set the counter to 0
    2.95 +      WinRing0.Wrmsr(PERF_CTR_0, 0, 0);
    2.96 +
    2.97 +      long ticks = (long)(timeWindow * Stopwatch.Frequency);
    2.98 +      uint lsbBegin, msbBegin, lsbEnd, msbEnd;
    2.99 +
   2.100 +      long timeBegin = Stopwatch.GetTimestamp() +
   2.101 +        (long)Math.Ceiling(0.001 * ticks);
   2.102 +      long timeEnd = timeBegin + ticks;
   2.103 +      while (Stopwatch.GetTimestamp() < timeBegin) { }
   2.104 +      WinRing0.Rdmsr(PERF_CTR_0, out lsbBegin, out msbBegin);
   2.105 +      while (Stopwatch.GetTimestamp() < timeEnd) { }
   2.106 +      WinRing0.Rdmsr(PERF_CTR_0, out lsbEnd, out msbEnd);
   2.107 +
   2.108 +      WinRing0.Rdmsr(COFVID_STATUS, out eax, out edx);
   2.109 +      uint cpuDid = (eax >> 6) & 7;
   2.110 +      uint cpuFid = eax & 0x1F;
   2.111 +      double coreMultiplier = MultiplierFromIDs(cpuDid, cpuFid);
   2.112 +
   2.113 +      ulong countBegin = ((ulong)msbBegin << 32) | lsbBegin;
   2.114 +      ulong countEnd = ((ulong)msbEnd << 32) | lsbEnd;
   2.115 +
   2.116 +      double coreFrequency = 1e-6 * 
   2.117 +        (((double)(countEnd - countBegin)) * Stopwatch.Frequency) /
   2.118 +        (timeEnd - timeBegin);
   2.119 +
   2.120 +      double busFrequency = coreFrequency / coreMultiplier;
   2.121 +      return 0.5 * Math.Round(2 * TimeStampCounterFrequency / busFrequency);
   2.122 +    }
   2.123 +
   2.124      protected override uint[] GetMSRs() {
   2.125 -      return new uint[] { P_STATE_0, COFVID_STATUS };
   2.126 +      return new uint[] { PERF_CTL_0, PERF_CTR_0, P_STATE_0, COFVID_STATUS };
   2.127      }
   2.128  
   2.129      public override string GetReport() {
   2.130 @@ -94,12 +175,18 @@
   2.131        r.Append("Miscellaneous Control Address: 0x");
   2.132        r.AppendLine((miscellaneousControlAddress).ToString("X",
   2.133          CultureInfo.InvariantCulture));
   2.134 +      r.Append("Time Stamp Counter Multiplier: ");
   2.135 +      r.AppendLine(timeStampCounterMultiplier.ToString(
   2.136 +        CultureInfo.InvariantCulture));
   2.137 +      r.AppendLine();
   2.138 +
   2.139 +      r.Append(debug);
   2.140        r.AppendLine();
   2.141  
   2.142        return r.ToString();
   2.143      }
   2.144  
   2.145 -    private double MultiplierFromIDs(uint divisorID, uint frequencyID) {
   2.146 +    private static double MultiplierFromIDs(uint divisorID, uint frequencyID) {
   2.147        return 0.5 * (frequencyID + 0x10) / (1 << (int)divisorID);
   2.148      }
   2.149  
   2.150 @@ -118,35 +205,29 @@
   2.151          }
   2.152        }
   2.153  
   2.154 -      if (hasTSC) {
   2.155 +      if (HasTimeStampCounter) {
   2.156          double newBusClock = 0;
   2.157  
   2.158          for (int i = 0; i < coreClocks.Length; i++) {
   2.159            Thread.Sleep(1);
   2.160  
   2.161            uint curEax, curEdx;
   2.162 -          uint maxEax, maxEdx;
   2.163            if (WinRing0.RdmsrTx(COFVID_STATUS, out curEax, out curEdx,
   2.164 -            (UIntPtr)(1L << cpuid[i][0].Thread)) &&
   2.165 -            WinRing0.RdmsrTx(P_STATE_0, out maxEax, out maxEdx,
   2.166              (UIntPtr)(1L << cpuid[i][0].Thread))) 
   2.167            {
   2.168              // 8:6 CpuDid: current core divisor ID
   2.169              // 5:0 CpuFid: current core frequency ID
   2.170 -            uint curCpuDid = (curEax >> 6) & 7;
   2.171 -            uint curCpuFid = curEax & 0x1F;
   2.172 -            double multiplier = MultiplierFromIDs(curCpuDid, curCpuFid);
   2.173 +            uint cpuDid = (curEax >> 6) & 7;
   2.174 +            uint cpuFid = curEax & 0x1F;
   2.175 +            double multiplier = MultiplierFromIDs(cpuDid, cpuFid);
   2.176  
   2.177 -            // we assume that the max multiplier (used for the TSC) 
   2.178 -            // can be found in the P_STATE_0 MSR
   2.179 -            uint maxCpuDid = (maxEax >> 6) & 7;
   2.180 -            uint maxCpuFid = maxEax & 0x1F;
   2.181 -            double maxMultiplier = MultiplierFromIDs(maxCpuDid, maxCpuFid);
   2.182 -
   2.183 -            coreClocks[i].Value = (float)(multiplier * MaxClock / maxMultiplier);
   2.184 -            newBusClock = (float)(MaxClock / maxMultiplier);
   2.185 +            coreClocks[i].Value = 
   2.186 +              (float)(multiplier * TimeStampCounterFrequency / 
   2.187 +              timeStampCounterMultiplier);
   2.188 +            newBusClock = 
   2.189 +              (float)(TimeStampCounterFrequency / timeStampCounterMultiplier);
   2.190            } else {
   2.191 -            coreClocks[i].Value = (float)MaxClock;
   2.192 +            coreClocks[i].Value = (float)TimeStampCounterFrequency;
   2.193            }
   2.194          }
   2.195  
   2.196 @@ -155,6 +236,17 @@
   2.197            ActivateSensor(this.busClock);
   2.198          }
   2.199        }
   2.200 -    } 
   2.201 +    }
   2.202 +
   2.203 +    private static class NativeMethods {
   2.204 +      private const string KERNEL = "kernel32.dll";
   2.205 +
   2.206 +      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
   2.207 +      public static extern UIntPtr
   2.208 +        SetThreadAffinityMask(IntPtr handle, UIntPtr mask);
   2.209 +
   2.210 +      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
   2.211 +      public static extern IntPtr GetCurrentThread();
   2.212 +    }
   2.213    }
   2.214  }
     3.1 --- a/Hardware/CPU/GenericCPU.cs	Mon Sep 27 23:48:41 2010 +0000
     3.2 +++ b/Hardware/CPU/GenericCPU.cs	Thu Sep 30 16:51:09 2010 +0000
     3.3 @@ -55,13 +55,13 @@
     3.4      protected readonly int coreCount;
     3.5      protected readonly string name;
     3.6  
     3.7 -    protected readonly bool hasTSC;
     3.8 -    protected readonly bool invariantTSC;
     3.9 -    private readonly double estimatedMaxClock;
    3.10 +    private readonly bool hasTimeStampCounter;
    3.11 +    private readonly bool isInvariantTimeStampCounter;
    3.12 +    private readonly double estimatedTimeStampCounterFrequency;
    3.13  
    3.14      private ulong lastTimeStampCount;
    3.15      private long lastTime;
    3.16 -    private double maxClock;    
    3.17 +    private double timeStampCounterFrequency;    
    3.18  
    3.19      private readonly Vendor vendor;
    3.20  
    3.21 @@ -89,19 +89,19 @@
    3.22        this.coreCount = cpuid.Length;
    3.23        this.name = cpuid[0][0].Name;      
    3.24  
    3.25 -      // check if processor has TSC
    3.26 +      // check if processor has a TSC
    3.27        if (cpuid[0][0].Data.GetLength(0) > 1
    3.28          && (cpuid[0][0].Data[1, 3] & 0x10) != 0)
    3.29 -        hasTSC = true;
    3.30 +        hasTimeStampCounter = true;
    3.31        else
    3.32 -        hasTSC = false;
    3.33 +        hasTimeStampCounter = false;
    3.34  
    3.35 -      // check if processor supports invariant TSC 
    3.36 +      // check if processor supports an invariant TSC 
    3.37        if (cpuid[0][0].ExtData.GetLength(0) > 7
    3.38          && (cpuid[0][0].ExtData[7, 3] & 0x100) != 0)
    3.39 -        invariantTSC = true;
    3.40 +        isInvariantTimeStampCounter = true;
    3.41        else
    3.42 -        invariantTSC = false;
    3.43 +        isInvariantTimeStampCounter = false;
    3.44  
    3.45        if (coreCount > 1)
    3.46          totalLoad = new Sensor("CPU Total", 0, SensorType.Load, this, settings);
    3.47 @@ -119,30 +119,30 @@
    3.48            ActivateSensor(totalLoad);
    3.49        }
    3.50  
    3.51 -      if (hasTSC)
    3.52 -        estimatedMaxClock = EstimateMaxClock();
    3.53 +      if (hasTimeStampCounter)
    3.54 +        estimatedTimeStampCounterFrequency = EstimateTimeStampCounterFrequency();
    3.55        else
    3.56 -        estimatedMaxClock = 0;
    3.57 -      maxClock = estimatedMaxClock;
    3.58 +        estimatedTimeStampCounterFrequency = 0;
    3.59 +      timeStampCounterFrequency = estimatedTimeStampCounterFrequency;
    3.60  
    3.61        lastTimeStampCount = 0;
    3.62        lastTime = 0;
    3.63      }
    3.64  
    3.65 -    private static double EstimateMaxClock() {
    3.66 +    private static double EstimateTimeStampCounterFrequency() {
    3.67        // preload the function
    3.68 -      EstimateMaxClock(0);
    3.69 -      EstimateMaxClock(0);
    3.70 +      EstimateTimeStampCounterFrequency(0);
    3.71 +      EstimateTimeStampCounterFrequency(0);
    3.72  
    3.73 -      // estimate the max clock in MHz      
    3.74 -      List<double> estimatedMaxClocks = new List<double>(3);
    3.75 +      // estimate the frequency in MHz      
    3.76 +      List<double> estimatedFrequency = new List<double>(3);
    3.77        for (int i = 0; i < 3; i++)
    3.78 -        estimatedMaxClocks.Add(1e-6 * EstimateMaxClock(0.025));
    3.79 -      estimatedMaxClocks.Sort();
    3.80 -      return estimatedMaxClocks[1];
    3.81 +        estimatedFrequency.Add(1e-6 * EstimateTimeStampCounterFrequency(0.025));
    3.82 +      estimatedFrequency.Sort();
    3.83 +      return estimatedFrequency[1];
    3.84      }
    3.85  
    3.86 -    private static double EstimateMaxClock(double timeWindow) {
    3.87 +    private static double EstimateTimeStampCounterFrequency(double timeWindow) {
    3.88        long ticks = (long)(timeWindow * Stopwatch.Frequency);
    3.89        uint lsbBegin, msbBegin, lsbEnd, msbEnd;
    3.90  
    3.91 @@ -195,12 +195,13 @@
    3.92          Environment.NewLine);
    3.93        r.AppendFormat("Threads per Core: {0}{1}", cpuid[0].Length,
    3.94          Environment.NewLine);
    3.95 -      r.AppendLine("TSC: " +
    3.96 -        (hasTSC ? (invariantTSC ? "Invariant" : "Not Invariant") : "None"));
    3.97        r.AppendLine(string.Format(CultureInfo.InvariantCulture,
    3.98          "Timer Frequency: {0} MHz", Stopwatch.Frequency * 1e-6));
    3.99 +      r.AppendLine("Time Stamp Counter: " + (hasTimeStampCounter ? (
   3.100 +        isInvariantTimeStampCounter ? "Invariant" : "Not Invariant") : "None"));
   3.101        r.AppendLine(string.Format(CultureInfo.InvariantCulture,
   3.102 -        "Max Clock: {0} MHz", Math.Round(maxClock * 100) * 0.01));
   3.103 +        "Time Stamp Counter Frequency: {0} MHz",
   3.104 +        Math.Round(timeStampCounterFrequency * 100) * 0.01));   
   3.105        r.AppendLine();
   3.106  
   3.107        uint[] msrArray = GetMSRs();
   3.108 @@ -239,22 +240,27 @@
   3.109        get { return HardwareType.CPU; }
   3.110      }
   3.111  
   3.112 -    protected double MaxClock {
   3.113 -      get { return maxClock; }
   3.114 +    public bool HasTimeStampCounter {
   3.115 +      get { return hasTimeStampCounter; }
   3.116 +    }
   3.117 +
   3.118 +    public double TimeStampCounterFrequency {
   3.119 +      get { return timeStampCounterFrequency; }
   3.120      }
   3.121  
   3.122      public override void Update() {
   3.123 -      if (hasTSC) {
   3.124 +      if (hasTimeStampCounter) {
   3.125          uint lsb, msb;
   3.126          WinRing0.RdtscTx(out lsb, out msb, (UIntPtr)1);
   3.127          long time = Stopwatch.GetTimestamp();
   3.128          ulong timeStampCount = ((ulong)msb << 32) | lsb;
   3.129          double delta = ((double)(time - lastTime)) / Stopwatch.Frequency;
   3.130          if (delta > 0.5) {
   3.131 -          if (invariantTSC)
   3.132 -            maxClock = (timeStampCount - lastTimeStampCount) / (1e6 * delta);
   3.133 +          if (isInvariantTimeStampCounter)
   3.134 +            timeStampCounterFrequency = 
   3.135 +              (timeStampCount - lastTimeStampCount) / (1e6 * delta);
   3.136            else
   3.137 -            maxClock = estimatedMaxClock;
   3.138 +            timeStampCounterFrequency = estimatedTimeStampCounterFrequency;
   3.139  
   3.140            lastTimeStampCount = timeStampCount;
   3.141            lastTime = time;
     4.1 --- a/Hardware/CPU/IntelCPU.cs	Mon Sep 27 23:48:41 2010 +0000
     4.2 +++ b/Hardware/CPU/IntelCPU.cs	Thu Sep 30 16:51:09 2010 +0000
     4.3 @@ -145,7 +145,7 @@
     4.4        for (int i = 0; i < coreClocks.Length; i++) {
     4.5          coreClocks[i] =
     4.6            new Sensor(CoreString(i), i + 1, SensorType.Clock, this, settings);
     4.7 -        if (hasTSC)
     4.8 +        if (HasTimeStampCounter)
     4.9            ActivateSensor(coreClocks[i]);
    4.10        }
    4.11  
    4.12 @@ -182,7 +182,7 @@
    4.13          }
    4.14        }
    4.15  
    4.16 -      if (hasTSC) {
    4.17 +      if (HasTimeStampCounter) {
    4.18          double newBusClock = 0;
    4.19          uint eax, edx;
    4.20          for (int i = 0; i < coreClocks.Length; i++) {
    4.21 @@ -191,9 +191,10 @@
    4.22              (UIntPtr)(1L << cpuid[i][0].Thread))) {
    4.23              if (maxNehalemMultiplier > 0) { // Core i3, i5, i7
    4.24                uint nehalemMultiplier = eax & 0xff;
    4.25 -              coreClocks[i].Value =
    4.26 -                (float)(nehalemMultiplier * MaxClock / maxNehalemMultiplier);
    4.27 -              newBusClock = (float)(MaxClock / maxNehalemMultiplier);
    4.28 +              coreClocks[i].Value =(float)(nehalemMultiplier * 
    4.29 +                TimeStampCounterFrequency / maxNehalemMultiplier);
    4.30 +              newBusClock = 
    4.31 +                (float)(TimeStampCounterFrequency / maxNehalemMultiplier);
    4.32              } else { // Core 2
    4.33                uint multiplier = (eax >> 8) & 0x1f;
    4.34                uint maxMultiplier = (edx >> 8) & 0x1f;
    4.35 @@ -201,13 +202,15 @@
    4.36                uint factor = (multiplier << 1) | ((eax >> 14) & 1);
    4.37                uint maxFactor = (maxMultiplier << 1) | ((edx >> 14) & 1);
    4.38                if (maxFactor > 0) {
    4.39 -                coreClocks[i].Value = (float)(factor * MaxClock / maxFactor);
    4.40 -                newBusClock = (float)(2 * MaxClock / maxFactor);
    4.41 +                coreClocks[i].Value = 
    4.42 +                  (float)(factor * TimeStampCounterFrequency / maxFactor);
    4.43 +                newBusClock = 
    4.44 +                  (float)(2 * TimeStampCounterFrequency / maxFactor);
    4.45                }
    4.46              }
    4.47            } else { // Intel Pentium 4
    4.48 -            // if IA32_PERF_STATUS is not available, assume maxClock
    4.49 -            coreClocks[i].Value = (float)MaxClock;
    4.50 +            // if IA32_PERF_STATUS is not available, assume TSC frequency
    4.51 +            coreClocks[i].Value = (float)TimeStampCounterFrequency;
    4.52            }
    4.53          }
    4.54          if (newBusClock > 0) {
     5.1 --- a/Hardware/WinRing0.cs	Mon Sep 27 23:48:41 2010 +0000
     5.2 +++ b/Hardware/WinRing0.cs	Thu Sep 30 16:51:09 2010 +0000
     5.3 @@ -90,10 +90,13 @@
     5.4      public delegate bool ReadPciConfigDwordExDelegate(uint pciAddress, 
     5.5        uint regAddress, out uint value);
     5.6      public delegate bool WritePciConfigDwordExDelegate(uint pciAddress, 
     5.7 -      uint regAddress, uint value);
     5.8 +      uint regAddress, uint value);    
     5.9 +    public delegate bool RdtscDelegate(out uint eax, out uint edx);
    5.10      public delegate bool RdtscTxDelegate(out uint eax, out uint edx,
    5.11 +      UIntPtr threadAffinityMask);    
    5.12 +    public delegate bool WrmsrDelegate(uint index, uint eax, uint edx);
    5.13 +    public delegate bool WrmsrTxDelegate(uint index, uint eax, uint edx,
    5.14        UIntPtr threadAffinityMask);
    5.15 -    public delegate bool RdtscDelegate(out uint eax, out uint edx);
    5.16  
    5.17      private static readonly InitializeOlsDelegate InitializeOls = 
    5.18        CreateDelegate<InitializeOlsDelegate>("InitializeOls");
    5.19 @@ -116,10 +119,14 @@
    5.20        CreateDelegate<ReadPciConfigDwordExDelegate>("ReadPciConfigDwordEx");
    5.21      public static readonly WritePciConfigDwordExDelegate WritePciConfigDwordEx =
    5.22        CreateDelegate<WritePciConfigDwordExDelegate>("WritePciConfigDwordEx");
    5.23 -    public static readonly RdtscTxDelegate RdtscTx =
    5.24 -      CreateDelegate<RdtscTxDelegate>("RdtscTx");
    5.25      public static readonly RdtscDelegate Rdtsc =
    5.26        CreateDelegate<RdtscDelegate>("Rdtsc");
    5.27 +    public static readonly RdtscTxDelegate RdtscTx =
    5.28 +      CreateDelegate<RdtscTxDelegate>("RdtscTx");    
    5.29 +    public static readonly WrmsrDelegate Wrmsr =
    5.30 +      CreateDelegate<WrmsrDelegate>("Wrmsr");
    5.31 +    public static readonly WrmsrTxDelegate WrmsrTx =
    5.32 +      CreateDelegate<WrmsrTxDelegate>("WrmsrTx");
    5.33   
    5.34      private static T CreateDelegate<T>(string entryPoint) where T : class {
    5.35        DllImportAttribute attribute = new DllImportAttribute(GetDllName());
     6.1 --- a/Properties/AssemblyVersion.cs	Mon Sep 27 23:48:41 2010 +0000
     6.2 +++ b/Properties/AssemblyVersion.cs	Thu Sep 30 16:51:09 2010 +0000
     6.3 @@ -37,5 +37,5 @@
     6.4  
     6.5  using System.Reflection;
     6.6  
     6.7 -[assembly: AssemblyVersion("0.1.37.17")]
     6.8 -[assembly: AssemblyInformationalVersion("0.1.37.17 Alpha")]
     6.9 \ No newline at end of file
    6.10 +[assembly: AssemblyVersion("0.1.37.23")]
    6.11 +[assembly: AssemblyInformationalVersion("0.1.37.23 Alpha")]
    6.12 \ No newline at end of file