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

时间:2011-11-25 10:49:27

标签: c# .net windows wmi

我使用.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有三类系统:

  1. 首先是Vista +系统,其中Timestamp_Sys100NS是自UTC时代以来的时间刻度。
  2. 其次是一些Windows 2003系统,其中Timestamp_Sys100NS需要添加到Win32_OperatingSystem.LastBootUpTime才能获得合理的时间。
  3. 第三类是系统,其中进行上述添加仍会导致正确日期和时间之外的日期。
  4. 编辑5 :某些受影响的计算机可能是虚拟机,但不是全部。

3 个答案:

答案 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使用情况,那么匹配正常。只要你用这些值计算,我认为你可以忽略任何小于零的东西。