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 }