2011-11-25 66 views
18

我使用.NET的System.Management東西來監視一些使用WMI的計算機。我使用的查詢是這樣的:過去的WMI,負CPU使用率值和Timestamp_Sys100NS

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服務器。而且我顯然是not the only one with the same problem

編輯3: 我已經從Win32_OperatingSystem查詢LastBootUpTime,並補充說,到Timestamp_Sys100NSTimestamp_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; 

EDIT 4: 似乎有3類系統相對於Timestamp_Sys100NS

  1. 首先是Vista的+系統,其中Timestamp_Sys100NS是時間,因爲在UTC紀元蜱。
  2. 其次是一些Windows 2003系統,需要將Timestamp_Sys100NS添加到Win32_OperatingSystem.LastBootUpTime才能獲得合理的時間。
  3. 第三類是系統,上述添加仍然會導致日期和日期偏離正確的日期和時間。

編輯5:部分受影響的機器可能是虛擬機,但不是全部虛擬機。

+18

這意味着CPU正在使用你:) –

+0

你是如何將LastBootUpTime添加到TimeStamp_Sys100NS的?你做了什麼樣的轉換? – raz3r

+0

@ raz3r:我使用'System.DateTime(Int64)'ctor(需要滴答),並將其添加到LastBootUpTime。我將只能明天查看確切的細節。 – wilx

回答

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使用率,它匹配的罰款。我認爲只要你用這些數值計算,你就可以忽略小於零的任何東西。

+0

不幸的是,我正在使用正確的公式。 – wilx

+0

我不確定你還有什麼可以做的。根據您的發現,我會添加一個檢查來查看LastBootUpTime> Timestamp_Sys100NS是否爲印記不準確的直接指標。 WMI版本之間存在很多不一致之處。直到Windows 2003加入更好的網絡數據和計數器後,他們才真正開始變得過於有效。 這是僅在Windows 2003 R1上有可能嗎? x86與x64有區別嗎? 這是一個很棒的話題,我們中的很多人都可以從結果中受益。 – Xcalibur37

1

這聽起來像是一個標準的「時間同步」問題給我。

您系統的時鐘是...時鐘。在你的情況下,你的時鐘可能運行得很快(也許它在99%的實際時間內完成一分鐘),所以當你的計算機與外部時鐘同步時(例如通過Windows時間服務),你的系統時間會跳回去。

或者,用戶可以手動調整系統時間(如:日期和時間控制面板),所以它的東西,你應該設計(如果設置他們的系統的時候崩潰您的應用程序用戶會很不高興的!)

我解決這個問題的方法是夾緊。始終需要至少0.0秒的「實時」通過,但也要鉗制到最大0.5秒,因爲時間調整可能會向前跳躍,而不僅僅是向後跳躍。

我希望有幫助。

+0

別忘了一個0。0秒的最低意味着你需要注意分開的零也 – JasonS

+0

我很確定這是你的問題,所以如果我的解決方案工作,請回復msg,或者如果它最終成爲別的東西(假設你讀了你的月份老問題) – JasonS

+0

不好的時間信息效果是一致的,它不會一次只發生一次,而是一直髮生。我的代碼每5秒檢查一次。 NTP守護進程/服務可以逐步調整時間,這似乎足夠長了。我什麼也不做,你的答案解釋了這個問題。 – wilx