WMI,负CPU使用率值和过去的Timestamp_Sys100NS

本文关键字:过去 Timestamp Sys100NS CPU 使用率 WMI | 更新日期: 2023-09-27 18:15:37

我正在使用WMI监控一些机器,使用。net的System.Management的东西。我使用的查询是这样的:

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日纪元开始的刻度),而是看起来像从启动时间开始的刻度。

编辑2 :我现在已经证实,这个问题在很多Windows 2003服务器上都存在。显然,我不是唯一一个有同样问题的人。

3 编辑:我通过从Win32_OperatingSystem查询LastBootUpTime并在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简单地添加到WMI在Timestamp_Sys100NS字段返回的时间戳(current)上…

if (time.Year < 2000)
    time = boot_time + current;

编辑4 :关于Timestamp_Sys100NS,似乎有3类系统:

  1. 首先是Vista+系统,其中Timestamp_Sys100NS是自UTC纪元以来的滴答时间。
  2. 第二是一些Windows 2003系统,Timestamp_Sys100NS需要添加到Win32_OperatingSystem.LastBootUpTime以获得合理的时间。
  3. 第三类是执行上述添加操作仍然导致日期和时间偏离正确日期和时间的系统。

EDIT 5:一些受影响的机器可能是vm,但不是全部。

WMI,负CPU使用率值和过去的Timestamp_Sys100NS

这听起来像是一个标准的"时间同步"问题。

你的系统时钟是…一个时钟。在你的情况下,你的时钟可能运行得很快(也许它在99%的实际时间内完成了一分钟),所以当你的计算机与外部时钟同步时(例如通过Windows时间服务),你的系统时间将向后跳。

或者,用户可以手动调整系统时间(例如:日期和时间控制面板),所以这是你应该设计的东西(如果设置他们的系统时间导致应用程序崩溃,你的用户会非常不高兴的!)

我解决这个问题的方法是夹紧。总是要求至少0.0秒的"实时"通过,但也要箝制到最大0.5秒,因为时间调整可能会向前跳跃,而不仅仅是向后。

尝试在该机器上使用代码创建应用程序,看看是否得到正确的读数http://www.microsoft.com/download/en/details.aspx?id=8572

您具体谈论的公式是PERF_100NSEC_TIMER_INVhttp://msdn.microsoft.com/en-us/library/ms803963.aspx

我个人没有处理过这个问题,因为我从未见过低于0的值。

这就是我一直在做的:

/// <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使用情况,它匹配得很好。我认为你可以忽略任何小于0的东西,只要你用这些值计算。