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.

This commit is contained in:
Michael Möller
2010-03-09 22:27:10 +00:00
parent 6cf8aef52c
commit 992b38ae20
3 changed files with 110 additions and 51 deletions

View File

@@ -39,6 +39,7 @@ using System;
using System.Collections.Generic;
using System.Drawing;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
@@ -63,11 +64,14 @@ namespace OpenHardwareMonitor.Hardware.CPU {
private uint logicalProcessors;
private uint logicalProcessorsPerCore;
private uint coreCount;
private ulong affinityMask;
private bool hasTSC;
private bool invariantTSC;
private double estimatedMaxClock;
private ulong affinityMask;
private CPULoad cpuLoad;
private ulong lastCount;
private ulong lastTimeStampCount;
private long lastTime;
private uint maxNehalemMultiplier = 0;
@@ -239,13 +243,33 @@ namespace OpenHardwareMonitor.Hardware.CPU {
ActivateSensor(totalLoad);
}
lastCount = 0;
// check if processor has TSC
if (cpuidData.GetLength(0) > 1 && (cpuidData[1, 3] & 0x10) != 0)
hasTSC = true;
else
hasTSC = false;
// check if processor supports invariant TSC
if (cpuidExtData.GetLength(0) > 7 && (cpuidExtData[7, 3] & 0x100) != 0)
invariantTSC = true;
else
invariantTSC = false;
// preload the function
EstimateMaxClock(0);
EstimateMaxClock(0);
// estimate the max clock in MHz
estimatedMaxClock = 1e-6 * EstimateMaxClock(0.01);
lastTimeStampCount = 0;
lastTime = 0;
busClock = new Sensor("Bus Speed", 0, SensorType.Clock, this);
coreClocks = new Sensor[coreCount];
for (int i = 0; i < coreClocks.Length; i++) {
coreClocks[i] =
new Sensor(CoreString(i), i + 1, SensorType.Clock, this);
if (hasTSC)
ActivateSensor(coreClocks[i]);
}
@@ -290,6 +314,12 @@ namespace OpenHardwareMonitor.Hardware.CPU {
Environment.NewLine);
r.AppendFormat("Affinity Mask: 0x{0}{1}", affinityMask.ToString("X"),
Environment.NewLine);
r.AppendLine("TSC: " +
(hasTSC ? (invariantTSC ? "Invariant" : "Not Invariant") : "None"));
r.AppendLine(string.Format(CultureInfo.InvariantCulture,
"Timer Frequency: {0} MHz", Stopwatch.Frequency * 1e-6));
r.AppendLine(string.Format(CultureInfo.InvariantCulture,
"Max Clock: {0} MHz", Math.Round(estimatedMaxClock * 100) * 0.01));
r.AppendLine();
for (int i = 0; i < coreCount; i++) {
@@ -306,14 +336,33 @@ namespace OpenHardwareMonitor.Hardware.CPU {
return r.ToString();
}
private double EstimateMaxClock(double timeWindow) {
long ticks = (long)(timeWindow * Stopwatch.Frequency);
uint lsbBegin, msbBegin, lsbEnd, msbEnd;
Thread.BeginThreadAffinity();
long timeBegin = Stopwatch.GetTimestamp() + 2;
long timeEnd = timeBegin + ticks;
while (Stopwatch.GetTimestamp() < timeBegin) { }
WinRing0.Rdtsc(out lsbBegin, out msbBegin);
while (Stopwatch.GetTimestamp() < timeEnd) { }
WinRing0.Rdtsc(out lsbEnd, out msbEnd);
Thread.EndThreadAffinity();
ulong countBegin = ((ulong)msbBegin << 32) | lsbBegin;
ulong countEnd = ((ulong)msbEnd << 32) | lsbEnd;
return (((double)(countEnd - countBegin)) * Stopwatch.Frequency) /
(timeEnd - timeBegin);
}
public void Update() {
for (int i = 0; i < coreTemperatures.Length; i++) {
uint eax, edx;
if (WinRing0.RdmsrTx(
IA32_THERM_STATUS_MSR, out eax, out edx,
(UIntPtr)(1 << (int)(logicalProcessorsPerCore * i))))
{
(UIntPtr)(1 << (int)(logicalProcessorsPerCore * i)))) {
// if reading is valid
if ((eax & 0x80000000) != 0) {
// get the dist from tjMax from bits 22:16
@@ -336,13 +385,19 @@ namespace OpenHardwareMonitor.Hardware.CPU {
totalLoad.Value = cpuLoad.GetTotalLoad();
}
if (hasTSC) {
uint lsb, msb;
bool valid = WinRing0.RdtscTx(out lsb, out msb, (UIntPtr)1);
WinRing0.RdtscTx(out lsb, out msb, (UIntPtr)1);
long time = Stopwatch.GetTimestamp();
ulong count = ((ulong)msb << 32) | lsb;
ulong timeStampCount = ((ulong)msb << 32) | lsb;
double delta = ((double)(time - lastTime)) / Stopwatch.Frequency;
if (valid && delta > 0.5) {
double maxClock = (count - lastCount) / (1e6 * delta);
if (delta > 0.5) {
double maxClock;
if (invariantTSC)
maxClock = (timeStampCount - lastTimeStampCount) / (1e6 * delta);
else
maxClock = estimatedMaxClock;
double busClock = 0;
uint eax, edx;
for (int i = 0; i < coreClocks.Length; i++) {
@@ -375,8 +430,9 @@ namespace OpenHardwareMonitor.Hardware.CPU {
ActivateSensor(this.busClock);
}
}
lastCount = count;
lastTimeStampCount = timeStampCount;
lastTime = time;
}
}
}
}

View File

@@ -97,6 +97,7 @@ namespace OpenHardwareMonitor.Hardware {
uint regAddress, uint value);
public delegate bool RdtscTxDelegate(out uint eax, out uint edx,
UIntPtr threadAffinityMask);
public delegate bool RdtscDelegate(out uint eax, out uint edx);
private static InitializeOlsDelegate InitializeOls;
private static DeinitializeOlsDelegate DeinitializeOls;
@@ -114,6 +115,7 @@ namespace OpenHardwareMonitor.Hardware {
public static ReadPciConfigDwordExDelegate ReadPciConfigDwordEx;
public static WritePciConfigDwordExDelegate WritePciConfigDwordEx;
public static RdtscTxDelegate RdtscTx;
public static RdtscDelegate Rdtsc;
private static void GetDelegate<T>(string entryPoint, out T newDelegate)
where T : class
@@ -142,6 +144,7 @@ namespace OpenHardwareMonitor.Hardware {
GetDelegate("ReadPciConfigDwordEx", out ReadPciConfigDwordEx);
GetDelegate("WritePciConfigDwordEx", out WritePciConfigDwordEx);
GetDelegate("RdtscTx", out RdtscTx);
GetDelegate("Rdtsc", out Rdtsc);
try {
if (InitializeOls != null && InitializeOls())

View File

@@ -69,5 +69,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("0.1.26.1")]
[assembly: AssemblyFileVersion("0.1.26.1")]
[assembly: AssemblyVersion("0.1.27.0")]
[assembly: AssemblyFileVersion("0.1.27.0")]