2014-11-20 29 views
2

今天我在工作中被要求創建一個工具,讓最終用戶在遇到「性能問題」時運行它。這是對越來越多的幾臺計算機和/或應用程序遇到極端性能問題的報告的反應。由於大量的報告,我們需要這些數據收集自動發生,所以我們可以在以後深入數據。以計算機「性能快照」

我已經設置了一個後端來收集信息,並且已經收集了一堆信息,但是我在收集進程的性能數據時遇到了問題。這是我看着:

1)使用System.Diagnotics.Process.GetProcesses():

這讓我所有正在運行的特效,這是很好的一個列表,但是這需要應用程序能夠運行顯然提升了,因爲每當我想要收集UserProcessorTime時它都會拋出異常,即使這些信息對於任務管理器中的每個非管理用戶來說都適用於他自己的進程。即使作爲成熟的管理員用戶運行,它也會引發異常。

2)使用的PerformanceCounter

性能計數器似乎很強大,但我已經遇到了麻煩,通過匹配的進程ID性能計數器,它似乎性能計數器大多用於在一段時間內跟蹤性能。情況並非如此。我們主要是在尋找一種進程失控的模式。

基本上,我們正在尋找(或多或少)是在任務管理器的進程列表(進程名稱,CPU週期,私有內存使用情況)中顯示的信息的快速快照,而且無需應用程序運行提升(進程列表可以限制爲用戶特效)。這與我所問的是一致的。

編輯:下面是一些代碼,我試圖用,很抱歉不能提供任何早期

下面是試圖使用性能計數器來獲得「%處理器時間」和實例「工作集 - 私人」適用於所有流程。

PerformanceCounterCategory perfCategory = PerformanceCounterCategory.GetCategories().First(c => c.CategoryName == "Process"); 
Console.WriteLine("{0} [{1}]", perfCategory.CategoryName, perfCategory.CategoryType); 
string[] instanceNames = perfCategory.GetInstanceNames(); 

if (instanceNames.Length > 0) 
{ 
    foreach (string instanceName in instanceNames) 
    { 
     Console.WriteLine(" {0}", instanceName); 
     PerformanceCounter[] counters = perfCategory.GetCounters(instanceName); 

     foreach (PerformanceCounter counter in counters) 
     { 
      if (counter.CounterName == "Working Set - Private") 
      { 
       Console.WriteLine("  {0} - {1}", counter.CounterName, counter.RawValue, counter.RawValue/1024); 
      } 
      if (counter.CounterName == "% Processor Time") 
      { 
       Console.WriteLine("  {0} - {1}", counter.CounterName, counter.RawValue); 
      } 
     } 
    } 
} 

爲「工作集 - 私人」的結果是斑上,但對於「%處理器時間」,這些價值觀毫無任何意義。

下面是輸出的一個例子,你可以看到,處理器時間百分比結果毫無任何意義:

WDExpress#1 
    % Processor Time - 378146424 
    Working Set - Private - 136257536 
taskhost 
    % Processor Time - 129480830 
    Working Set - Private - 1835008 
svchost 
    % Processor Time - 2877438445 
    Working Set - Private - 4096000 
IpOverUsbSvc 
    % Processor Time - 15600100 
    Working Set - Private - 1236992 
vncserver 
    % Processor Time - 238213527 
    Working Set - Private - 2555904 
chrome#21 
    % Processor Time - 1652830595 
    Working Set - Private - 56799232 

編輯2:

斯科特已經提供了答案的很大一部分,但我現在仍然面臨着其他問題,下面兩個選項:

  1. 快速,準確,炸彈CPU

    counter.NextValue(); 
    Console.WriteLine("{0} - {1}", counter.CounterName, counter.NextValue()); 
    

調用NextValue()後,兩次對方收集數據非常快,但相當多轟擊我的CPU(和結果可能是次優的)。

  • 準確,速度很慢,容易在CPU

    counter.NextValue(); 
    System.Threading.Thread.Sleep(1000); 
    Console.WriteLine("{0} - {1}", counter.CounterName, counter.NextValue()); 
    
  • 另一種選擇是將每個呼叫到NextValue之間Thread.sleep代碼()上() ,但這使得它非常慢(因爲我們可能談論的是100多個進程)

    +0

    而你的問題是什麼?如何處理你所嘗試的代碼片段? – techvice 2014-11-20 22:40:15

    +0

    「我基本上可以如何快速查看任務管理器進程列表中顯示的信息(進程名稱,cpu週期,專用內存使用情況),而不需要應用程序運行提升」。我沒有提供任何代碼片斷,因爲我沒有任何編寫代碼的麻煩,我只是不確定要使用哪些組件。另外我在睡覺之前寫下了這個:) – 2014-11-20 22:44:43

    +0

    如何使用WMI訪問流程信息?有些是這樣的:http://www.codeproject.com/Articles/12138/Process-Information-and-Notifications-using-WMI – techvice 2014-11-20 22:49:33

    回答

    2

    你的處理器時間問題是你不應該使用RawValue就可以了(你真的不應該使用它作爲工作集) 。對於處理器時間,您必須帶兩個樣品呼叫NextValue,您會得到第二個樣品,您將獲得準確的數字。

    PerformanceCounterCategory perfCategory = PerformanceCounterCategory.GetCategories().First(c => c.CategoryName == "Process"); 
    Console.WriteLine("{0} [{1}]", perfCategory.CategoryName, perfCategory.CategoryType); 
    string[] instanceNames = perfCategory.GetInstanceNames(); 
    
    if (instanceNames.Length > 0) 
    { 
        foreach (string instanceName in instanceNames) 
        { 
         Console.WriteLine(" {0}", instanceName); 
         PerformanceCounter[] counters = perfCategory.GetCounters(instanceName); 
    
         //Go through each processor counter once to get the first value, should just return 0. 
         foreach (PerformanceCounter counter in counters) 
         { 
          if (counter.CounterName == "% Processor Time") 
          { 
           counter.NextValue(); 
          }    
         } 
    
         //You need to wait at least 100ms between samples to get useful values, the longer you wait the better the reading. 
         Thread.Sleep(150); 
    
         foreach (PerformanceCounter counter in counters) 
         { 
          if (counter.CounterName == "Working Set - Private") 
          { 
           Console.WriteLine("  {0} - {1}", counter.CounterName, counter.RawValue, counter.RawValue/1024); 
          } 
          if (counter.CounterName == "% Processor Time") 
          { 
           Console.WriteLine("  {0} - {1:N1}", counter.CounterName, counter.NextValue()); 
          } 
         } 
        } 
    } 
    
    +0

    謝謝!那樣做了。我之前嘗試過使用NextValue(),但我認爲它會在初始化和第一次調用NextValue()之間進行度量,所以我只用了一次。儘管如此,仍有一些麻煩。在彼此之後兩次調用NextValue()以非常快的速度收集數據,但幾乎會轟炸我的CPU(並且結果可能不是最佳的)。另一種選擇是每次調用NextValue()之間的Thread.Sleep(),但這會使其非常緩慢(因爲我們可能在談論100多個進程) – 2014-11-23 01:57:18

    +0

    對於您編輯的「快速不準確的炸彈CPU」解決方案對於你的問題,你忽略了我在例子中提出的評論:「你需要在樣本之間等待至少100ms才能獲得有用的值,你等待閱讀的時間越長。」如果你沒有等待至少100ms,你只會得到0或100從NextValue的結果,請參見[這是我的舊答案](http://stackoverflow.com/questions/8462331/i-need-to-call-accurate-cpu-usage-of-a-single-過程/ 8462977#8462977)瞭解更多信息。不要每個進程等待一次,讀取所有進程一次,等待100毫秒一次,然後再次讀取所有進程。 – 2014-11-23 03:04:32

    +0

    好的答案,我從來沒有想過只爲所有計數器執行一次Thread.Sleep,實際上應該始終如此。不像其他所有其他的例子,在每個櫃檯都進行了睡眠(我猜是因爲問題總是單計數器) – 2015-05-12 16:10:34