我使用.NET的System.Management
内容监视一些使用WMI的计算机。我正在使用的查询是:
SELECT Timestamp_Sys100NS, PercentProcessorTime
FROM Win32_PerfRawData_PerfOS_Processor
WHERE Name='_Total'
从中我使用众所周知的公式计算CPU使用率:
double cpu_usage = (1 - (double)delta_cpu / delta_time) * 100;
除了一台(到目前为止),每台机器都能很好地工作。
问题是,对于一台机器,即Windows 2003服务器(启用了超线程,如果重要),我有时会得到负CPU使用率值。换句话说,(double)delta_cpu / delta_time
表达式产生数字> 1
。我确实在网上搜索了为什么会发生这种情况的提示,但我一无所获。
此Windows 2003服务器是否具体?或者是超线程相关的问题?或者只是预期,我应该将CPU使用值或cpu_delta
值限制在某个范围内?
编辑:
我用这台机器观察到的第二个奇怪的事情是Timestamp_Sys100NS
值并不表示FILETIME
类似日期(自1600年1月1日以来的刻度),而是从启动时开始看起来像滴答。 / p>
编辑2 : 我现在已经验证了这个问题出现在很多Windows 2003服务器上。我显然是not the only one with the same problem。
编辑3 :
我已经解决了时间戳问题,从LastBootUpTime
查询Win32_OperatingSystem
,并在Timestamp_Sys100NS
的值过去太远时将其添加到Timestamp_Sys100NS
。这似乎给出了正确的日期和时间。从Win32_OperatingSystem
检索日期后操纵日期的代码如下所示:
WbemScripting.SWbemDateTime swbem_time = new WbemScripting.SWbemDateTime();
swbem_time.Value = date_str;
string time_as_file_time_str = swbem_time.GetFileTime(true);
return new DateTimeOffset(epoch.Ticks + long.Parse(time_as_file_time_str),
swbem_time.UTCSpecified
? TimeSpan.FromMinutes(swbem_time.UTC)
: TimeSpan.Zero);
...然后调整为UTC ......
boot_time = boot_time.UtcDateTime;
...然后将boot_time
添加到current
字段中WMI返回的时间戳(Timestamp_Sys100NS
)中...
if (time.Year < 2000)
time = boot_time + current;
编辑4 :
看来,Timestamp_Sys100NS
有三类系统:
Timestamp_Sys100NS
是自UTC时代以来的时间刻度。Timestamp_Sys100NS
需要添加到Win32_OperatingSystem.LastBootUpTime
才能获得合理的时间。编辑5 :某些受影响的计算机可能是虚拟机,但不是全部。
答案 0 :(得分:1)
这听起来像是一个标准的“时间同步”问题。
你的系统时钟是......一个时钟。在您的情况下,您的时钟可能正在快速运行(可能在99%的实际时间内完成一分钟),因此当您的计算机与外部时钟同步时(例如通过Windows时间服务),您的系统时间将向后跳跃。 / p>
或者,用户可以手动调整系统时间(例如:日期和时间控制面板),因此这是你应该设计的东西(如果设置系统的时间会使你的应用程序崩溃,你的用户会非常不高兴。)
我解决这个问题的方法是通过钳制。总是需要至少0.0秒的“实时”通过,但也可以锁定最多0.5秒,因为时间调整可能会向前跳跃,而不仅是向后。
我希望有所帮助。
答案 1 :(得分:0)
尝试在该计算机上使用代码创建应用程序,看看您是否获得了正确的读数 http://www.microsoft.com/download/en/details.aspx?id=8572
答案 2 :(得分:0)
您特别谈到的公式是PERF_100NSEC_TIMER_INV http://msdn.microsoft.com/en-us/library/ms803963.aspx
我没有亲自处理过这个问题,因为我从未见过低于零的值。
这就是我一直在做的事情:
/// <summary>
/// PERF_100NSEC_TIMER_INV algorithm.
/// </summary>
/// <param name="n2"></param>
/// <param name="d2"></param>
/// <param name="n1"></param>
/// <param name="d1"></param>
/// <returns></returns>
public static int CalculatePerf100NsecTimerInv(long n2, UInt64 d2,
long n1, UInt64 d1)
{
int usage = 0;
try
{
double dataDiff = (n2 - n1);
double timeDiff = (d2 - d1);
double dUsage = (1 - (dataDiff / timeDiff)) * 100;
// Evaluate
usage = (dUsage >= 0.5) ? Convert.ToInt32(Math.Ceiling(dUsage)) : 0;
}
catch { }
// Return
return usage;
}
用法:
// Calculate
int cpuTime =
MSPerformanceAlgorithms.CalculatePerf100NsecTimerInv(
current.PercentProcessorTime, current.TimestampSys100Ns,
previous.PercentProcessorTime, previous.TimestampSys100Ns);
如果我在2003年框的任务管理器上观察CPU使用情况,那么匹配正常。只要你用这些值计算,我认为你可以忽略任何小于零的东西。