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

我正在监视一些使用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_timeexpression式产生> 1数字。 我没有searchnetworking提示为什么这可能会发生,但我什么也没find。

这个Windows 2003服务器是特定的吗? 或者是超线程相关的问题? 还是只是预期,我应该把CPU使用率值或cpu_delta值限制在一定的范围内?

编辑:我观察与这一台机器的第二个奇怪的事情是, Timestamp_Sys100NS值不表示像FILETIME像date(自1600年1月1日以来的蜱),但它看起来像自引导时间以来的蜱。

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

编辑3 :我已经通过查询从Win32_OperatingSystem LastBootUpTime并添加到Timestamp_Sys100NS的值Timestamp_Sys100NS过去太远解决了时间戳问题。 这似乎给了正确的date和时间。 从Win32_OperatingSystem检索date后的代码操作如下所示:

 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 :看来,有3类系统相对于Timestamp_Sys100NS

  1. 首先是Vista +系统,其中Timestamp_Sys100NS是UTC以来的纪元时间。
  2. 其次是一些Windows 2003系统,需要将Timestamp_Sys100NS添加到Win32_OperatingSystem.LastBootUpTime以获得合理的时间。
  3. 第三类是这样的系统,上述添加仍然会导致正确的date和时间的date。

编辑5 :一些受影响的机器可能是虚拟机,但不是全部。

这听起来像是一个标准的“时间同步”问题给我。

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

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

我解决这个问题的方法是夹紧。 总是需要至少0.0秒的“实时”通过,而且还要钳制到最多0.5秒,因为时间调整可能会飞跃,不仅是向后跳跃。

我希望帮助。

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

您正在具体谈论的公式是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使用情况,它可以很好地匹配。 只要你用这些数值计算,我想你可以忽略小于零的任何东西。