Changed the CPU clock calculation. If no invariant TSC is available, then the max CPU clock is estimated at startup under load, otherwise an average over one second is used.
authormoel.mich
Tue, 09 Mar 2010 22:27:10 +0000
changeset 799cdbe1d8d12a
parent 78 52c16b1d5536
child 80 129a9a1d514f
Changed the CPU clock calculation. If no invariant TSC is available, then the max CPU clock is estimated at startup under load, otherwise an average over one second is used.
Hardware/CPU/IntelCPU.cs
Hardware/WinRing0.cs
Properties/AssemblyInfo.cs
     1.1 --- a/Hardware/CPU/IntelCPU.cs	Tue Mar 09 20:35:19 2010 +0000
     1.2 +++ b/Hardware/CPU/IntelCPU.cs	Tue Mar 09 22:27:10 2010 +0000
     1.3 @@ -39,6 +39,7 @@
     1.4  using System.Collections.Generic;
     1.5  using System.Drawing;
     1.6  using System.Diagnostics;
     1.7 +using System.Globalization;
     1.8  using System.Reflection;
     1.9  using System.Runtime.InteropServices;
    1.10  using System.Threading;
    1.11 @@ -63,13 +64,16 @@
    1.12      private uint logicalProcessors;
    1.13      private uint logicalProcessorsPerCore;
    1.14      private uint coreCount;
    1.15 +    private bool hasTSC;
    1.16 +    private bool invariantTSC;    
    1.17 +    private double estimatedMaxClock;
    1.18 +
    1.19      private ulong affinityMask;
    1.20 -
    1.21      private CPULoad cpuLoad;
    1.22  
    1.23 -    private ulong lastCount;    
    1.24 +    private ulong lastTimeStampCount;    
    1.25      private long lastTime;
    1.26 -    private uint maxNehalemMultiplier = 0;
    1.27 +    private uint maxNehalemMultiplier = 0;    
    1.28      
    1.29      private const uint IA32_THERM_STATUS_MSR = 0x019C;
    1.30      private const uint IA32_TEMPERATURE_TARGET = 0x01A2;
    1.31 @@ -239,14 +243,34 @@
    1.32            ActivateSensor(totalLoad);
    1.33        }
    1.34  
    1.35 -      lastCount = 0;
    1.36 +      // check if processor has TSC
    1.37 +      if (cpuidData.GetLength(0) > 1 && (cpuidData[1, 3] & 0x10) != 0)
    1.38 +        hasTSC = true;
    1.39 +      else
    1.40 +        hasTSC = false; 
    1.41 +
    1.42 +      // check if processor supports invariant TSC 
    1.43 +      if (cpuidExtData.GetLength(0) > 7 && (cpuidExtData[7, 3] & 0x100) != 0)
    1.44 +        invariantTSC = true;
    1.45 +      else
    1.46 +        invariantTSC = false;
    1.47 +
    1.48 +      // preload the function
    1.49 +      EstimateMaxClock(0); 
    1.50 +      EstimateMaxClock(0); 
    1.51 +
    1.52 +      // estimate the max clock in MHz      
    1.53 +      estimatedMaxClock = 1e-6 * EstimateMaxClock(0.01);
    1.54 +
    1.55 +      lastTimeStampCount = 0;
    1.56        lastTime = 0;
    1.57        busClock = new Sensor("Bus Speed", 0, SensorType.Clock, this);      
    1.58        coreClocks = new Sensor[coreCount];
    1.59        for (int i = 0; i < coreClocks.Length; i++) {
    1.60          coreClocks[i] =
    1.61            new Sensor(CoreString(i), i + 1, SensorType.Clock, this);
    1.62 -        ActivateSensor(coreClocks[i]);
    1.63 +        if (hasTSC)
    1.64 +          ActivateSensor(coreClocks[i]);
    1.65        }
    1.66        
    1.67        Update();                   
    1.68 @@ -289,7 +313,13 @@
    1.69        r.AppendFormat("Threads per Core: {0}{1}", logicalProcessorsPerCore,
    1.70          Environment.NewLine);
    1.71        r.AppendFormat("Affinity Mask: 0x{0}{1}", affinityMask.ToString("X"),
    1.72 -        Environment.NewLine);  
    1.73 +        Environment.NewLine);
    1.74 +      r.AppendLine("TSC: " + 
    1.75 +        (hasTSC ? (invariantTSC ? "Invariant" : "Not Invariant") : "None"));
    1.76 +      r.AppendLine(string.Format(CultureInfo.InvariantCulture, 
    1.77 +        "Timer Frequency: {0} MHz", Stopwatch.Frequency * 1e-6));
    1.78 +      r.AppendLine(string.Format(CultureInfo.InvariantCulture,
    1.79 +        "Max Clock: {0} MHz", Math.Round(estimatedMaxClock * 100) * 0.01));
    1.80        r.AppendLine();
    1.81  
    1.82        for (int i = 0; i < coreCount; i++) {
    1.83 @@ -306,14 +336,33 @@
    1.84        return r.ToString();
    1.85      }
    1.86  
    1.87 +    private double EstimateMaxClock(double timeWindow) {
    1.88 +      long ticks = (long)(timeWindow * Stopwatch.Frequency);
    1.89 +      uint lsbBegin, msbBegin, lsbEnd, msbEnd; 
    1.90 +      
    1.91 +      Thread.BeginThreadAffinity();
    1.92 +      long timeBegin = Stopwatch.GetTimestamp() + 2;
    1.93 +      long timeEnd = timeBegin + ticks;      
    1.94 +      while (Stopwatch.GetTimestamp() < timeBegin) { }
    1.95 +      WinRing0.Rdtsc(out lsbBegin, out msbBegin);
    1.96 +      while (Stopwatch.GetTimestamp() < timeEnd) { }
    1.97 +      WinRing0.Rdtsc(out lsbEnd, out msbEnd);
    1.98 +      Thread.EndThreadAffinity();
    1.99 +
   1.100 +      ulong countBegin = ((ulong)msbBegin << 32) | lsbBegin;
   1.101 +      ulong countEnd = ((ulong)msbEnd << 32) | lsbEnd;
   1.102 +
   1.103 +      return (((double)(countEnd - countBegin)) * Stopwatch.Frequency) / 
   1.104 +        (timeEnd - timeBegin);
   1.105 +    }
   1.106 +
   1.107      public void Update() {
   1.108 -            
   1.109 +
   1.110        for (int i = 0; i < coreTemperatures.Length; i++) {
   1.111          uint eax, edx;
   1.112          if (WinRing0.RdmsrTx(
   1.113 -          IA32_THERM_STATUS_MSR, out eax, out edx, 
   1.114 -            (UIntPtr)(1 << (int)(logicalProcessorsPerCore * i)))) 
   1.115 -        {
   1.116 +          IA32_THERM_STATUS_MSR, out eax, out edx,
   1.117 +            (UIntPtr)(1 << (int)(logicalProcessorsPerCore * i)))) {
   1.118            // if reading is valid
   1.119            if ((eax & 0x80000000) != 0) {
   1.120              // get the dist from tjMax from bits 22:16
   1.121 @@ -325,7 +374,7 @@
   1.122            } else {
   1.123              DeactivateSensor(coreTemperatures[i]);
   1.124            }
   1.125 -        }        
   1.126 +        }
   1.127        }
   1.128  
   1.129        if (cpuLoad.IsAvailable) {
   1.130 @@ -335,48 +384,55 @@
   1.131          if (totalLoad != null)
   1.132            totalLoad.Value = cpuLoad.GetTotalLoad();
   1.133        }
   1.134 -     
   1.135 -      uint lsb, msb;
   1.136 -      bool valid = WinRing0.RdtscTx(out lsb, out msb, (UIntPtr)1);
   1.137 -      long time = Stopwatch.GetTimestamp();
   1.138 -      ulong count = ((ulong)msb << 32) | lsb;
   1.139 -      double delta = ((double)(time - lastTime)) / Stopwatch.Frequency;
   1.140 -      if (valid && delta > 0.5) {
   1.141 -        double maxClock = (count - lastCount) / (1e6 * delta);
   1.142 -        double busClock = 0;
   1.143 -        uint eax, edx;
   1.144 -        for (int i = 0; i < coreClocks.Length; i++) {
   1.145 -          System.Threading.Thread.Sleep(1);
   1.146 -          if (WinRing0.RdmsrTx(IA32_PERF_STATUS, out eax, out edx,
   1.147 -            (UIntPtr)(1 << (int)(logicalProcessorsPerCore * i)))) {
   1.148 -            if (maxNehalemMultiplier > 0) { // Core i3, i5, i7
   1.149 -              uint nehalemMultiplier = eax & 0xff;
   1.150 -              coreClocks[i].Value =
   1.151 -                (float)(nehalemMultiplier * maxClock / maxNehalemMultiplier);
   1.152 -              busClock = (float)(maxClock / maxNehalemMultiplier);
   1.153 -            } else { // Core 2
   1.154 -              uint multiplier = (eax >> 8) & 0x1f;
   1.155 -              uint maxMultiplier = (edx >> 8) & 0x1f;
   1.156 -              // factor = multiplier * 2 to handle non integer multipliers 
   1.157 -              uint factor = (multiplier << 1) | ((eax >> 14) & 1);
   1.158 -              uint maxFactor = (maxMultiplier << 1) | ((edx >> 14) & 1);
   1.159 -              if (maxFactor > 0) {
   1.160 -                coreClocks[i].Value = (float)(factor * maxClock / maxFactor);
   1.161 -                busClock = (float)(2 * maxClock / maxFactor);
   1.162 +
   1.163 +      if (hasTSC) {
   1.164 +        uint lsb, msb;
   1.165 +        WinRing0.RdtscTx(out lsb, out msb, (UIntPtr)1);
   1.166 +        long time = Stopwatch.GetTimestamp();
   1.167 +        ulong timeStampCount = ((ulong)msb << 32) | lsb;
   1.168 +        double delta = ((double)(time - lastTime)) / Stopwatch.Frequency;
   1.169 +        if (delta > 0.5) {
   1.170 +          double maxClock;
   1.171 +          if (invariantTSC)
   1.172 +            maxClock = (timeStampCount - lastTimeStampCount) / (1e6 * delta);
   1.173 +          else
   1.174 +            maxClock = estimatedMaxClock;
   1.175 +
   1.176 +          double busClock = 0;
   1.177 +          uint eax, edx;
   1.178 +          for (int i = 0; i < coreClocks.Length; i++) {
   1.179 +            System.Threading.Thread.Sleep(1);
   1.180 +            if (WinRing0.RdmsrTx(IA32_PERF_STATUS, out eax, out edx,
   1.181 +              (UIntPtr)(1 << (int)(logicalProcessorsPerCore * i)))) {
   1.182 +              if (maxNehalemMultiplier > 0) { // Core i3, i5, i7
   1.183 +                uint nehalemMultiplier = eax & 0xff;
   1.184 +                coreClocks[i].Value =
   1.185 +                  (float)(nehalemMultiplier * maxClock / maxNehalemMultiplier);
   1.186 +                busClock = (float)(maxClock / maxNehalemMultiplier);
   1.187 +              } else { // Core 2
   1.188 +                uint multiplier = (eax >> 8) & 0x1f;
   1.189 +                uint maxMultiplier = (edx >> 8) & 0x1f;
   1.190 +                // factor = multiplier * 2 to handle non integer multipliers 
   1.191 +                uint factor = (multiplier << 1) | ((eax >> 14) & 1);
   1.192 +                uint maxFactor = (maxMultiplier << 1) | ((edx >> 14) & 1);
   1.193 +                if (maxFactor > 0) {
   1.194 +                  coreClocks[i].Value = (float)(factor * maxClock / maxFactor);
   1.195 +                  busClock = (float)(2 * maxClock / maxFactor);
   1.196 +                }
   1.197                }
   1.198 -            }  
   1.199 -          } else { // Intel Pentium 4
   1.200 -            // if IA32_PERF_STATUS is not available, assume maxClock
   1.201 -            coreClocks[i].Value = (float)maxClock;
   1.202 +            } else { // Intel Pentium 4
   1.203 +              // if IA32_PERF_STATUS is not available, assume maxClock
   1.204 +              coreClocks[i].Value = (float)maxClock;
   1.205 +            }
   1.206 +          }
   1.207 +          if (busClock > 0) {
   1.208 +            this.busClock.Value = (float)busClock;
   1.209 +            ActivateSensor(this.busClock);
   1.210            }
   1.211          }
   1.212 -        if (busClock > 0) {
   1.213 -          this.busClock.Value = (float)busClock;
   1.214 -          ActivateSensor(this.busClock);
   1.215 -        }
   1.216 +        lastTimeStampCount = timeStampCount;
   1.217 +        lastTime = time;
   1.218        }
   1.219 -      lastCount = count;
   1.220 -      lastTime = time;
   1.221      }
   1.222    }  
   1.223  }
     2.1 --- a/Hardware/WinRing0.cs	Tue Mar 09 20:35:19 2010 +0000
     2.2 +++ b/Hardware/WinRing0.cs	Tue Mar 09 22:27:10 2010 +0000
     2.3 @@ -97,6 +97,7 @@
     2.4        uint regAddress, uint value);
     2.5      public delegate bool RdtscTxDelegate(out uint eax, out uint edx,
     2.6        UIntPtr threadAffinityMask);
     2.7 +    public delegate bool RdtscDelegate(out uint eax, out uint edx);
     2.8  
     2.9      private static InitializeOlsDelegate InitializeOls;
    2.10      private static DeinitializeOlsDelegate DeinitializeOls;
    2.11 @@ -114,6 +115,7 @@
    2.12      public static ReadPciConfigDwordExDelegate ReadPciConfigDwordEx;
    2.13      public static WritePciConfigDwordExDelegate WritePciConfigDwordEx;
    2.14      public static RdtscTxDelegate RdtscTx;
    2.15 +    public static RdtscDelegate Rdtsc;
    2.16  
    2.17      private static void GetDelegate<T>(string entryPoint, out T newDelegate) 
    2.18        where T : class 
    2.19 @@ -142,6 +144,7 @@
    2.20        GetDelegate("ReadPciConfigDwordEx", out ReadPciConfigDwordEx);
    2.21        GetDelegate("WritePciConfigDwordEx", out WritePciConfigDwordEx);
    2.22        GetDelegate("RdtscTx", out RdtscTx);
    2.23 +      GetDelegate("Rdtsc", out Rdtsc);
    2.24  
    2.25        try {
    2.26          if (InitializeOls != null && InitializeOls())
     3.1 --- a/Properties/AssemblyInfo.cs	Tue Mar 09 20:35:19 2010 +0000
     3.2 +++ b/Properties/AssemblyInfo.cs	Tue Mar 09 22:27:10 2010 +0000
     3.3 @@ -69,5 +69,5 @@
     3.4  // You can specify all the values or you can default the Build and Revision Numbers 
     3.5  // by using the '*' as shown below:
     3.6  // [assembly: AssemblyVersion("1.0.*")]
     3.7 -[assembly: AssemblyVersion("0.1.26.1")]
     3.8 -[assembly: AssemblyFileVersion("0.1.26.1")]
     3.9 +[assembly: AssemblyVersion("0.1.27.0")]
    3.10 +[assembly: AssemblyFileVersion("0.1.27.0")]