2013-04-10 20 views
14

好吧,所以我基本上試圖創建一個安裝的性能計數器類別的列表,就像你在PerfMon中得到的那樣。對於這個我使用PerformanceCounterCategory.GetCategories與Perfmon不一致

System.Diagnostics.PerformanceCounterCategory.GetCategories() 

這似乎是它的工作原理,直到你檢查清單,並找出一些缺失。我發現第一個失蹤的是ReadyBoost Cache。這是因爲該項目設置爲在「x86」上編譯。將其更改爲「任何CPU」可解決該問題。例如,其中一臺測試機器有一個「授權管理器應用程序」(Authorization Manager Applications)類別(我的不知道,沒有人知道爲什麼,或者它來自哪裏)。但是,在該機器上,性能計數器類別在PerfMon中顯示,但在從C#調用GetCategories()方法時不顯示。

有誰知道爲什麼?有沒有更可靠的方法來獲得PerformanceCounterCategories?這是因爲我使用.Net嗎?是否有一些我可以使用的原生API?

編輯

我很抱歉,我還是不明白這一點。我寫了這段代碼或許更好地說明它:

using System; 
using System.Diagnostics; 
using System.Linq; 
using System.Text.RegularExpressions; 
using Microsoft.Win32; 

namespace PccHack 
{ 
    class Program 
    { 
     private static readonly Regex Numeric = new Regex(@"^\d+$"); 
     static void Main(string[] args) 
     { 
      var pcc1 = PerformanceCounterCategory.GetCategories(); 
      Console.Out.WriteLine("Getting automatically from the microsoft framework gave {0} results.", pcc1.Count()); 
      string[] counters; 
      using (var regKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009")) 
      { 
       counters = regKey.GetValue("Counter") as string[]; 
      } 
      var pcc2 = counters.Where(counter => !Numeric.IsMatch(counter)).ToList(); 
      pcc2.Sort(); 
      Console.Out.WriteLine("Getting manually from the registry gave {0} results.", pcc2.Count()); 
      Console.In.ReadLine(); 
     } 
    } 
} 

這現在給我3236個結果。因爲它獲得了系統中的所有性能計數器。所以我想我需要做的就是過濾那些實際上是性能計數器的東西,只留下類別。然而,似乎沒有一個PerformanceCounter的構造函數,它只接受名稱(因爲這不是唯一的),似乎也沒有采用索引值的構造函數。我發現了一個名爲Performance Data Helper的Win32 API,但這似乎並沒有我想要的功能。所以。如果我有一個性能計數器索引,那麼在C#中如何獲取該索引的PerformanceCounterCategory? PerfMon做到了,所以它一定是可能的。有什麼方法可以解析索引「幻數」來找出哪個是哪個?

編輯2

好。因此,這是做我的頭在最新版本中使用三種不同的方法(.NET /註冊表/ PowerShell中)的代碼提示的:

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using System.Linq; 
using System.Reflection; 
using Microsoft.Win32; 
using System.Management.Automation; 


namespace PccHack 
{ 
    internal class Program 
    { 
     private static void Main() 
     { 
      var counterMap = new Dictionary<string, string>(); 
      using (var regKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009")) 
      { 
       var counter = regKey.GetValue("Counter") as string[]; 
       for (var i = 0; i < counter.Count() - 1; i += 2) 
       { 
        counterMap.Add(counter[i], counter[i + 1]); 
       } 
      } 

      var pcc1 = PerformanceCounterCategory.GetCategories().Select(o => o.CategoryName).ToList(); 
      var pcc2 = new List<string>(); 
      // Get v1 providers 
      using (var regKey = Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\services")) 
      { 
       foreach (var subKeyName in regKey.GetSubKeyNames()) 
       { 
        using (var subKey = regKey.OpenSubKey(subKeyName)) 
        { 
         if (!subKey.GetSubKeyNames().Contains("Performance")) continue; 
         using (var perfKey = subKey.OpenSubKey("Performance")) 
         { 
          var blah = (string) perfKey.GetValue("Object List"); 
          if (blah != null) 
          { 
           pcc2.AddRange(blah.Split(' ').Select(b => counterMap[b])); 
          } 
         } 
        } 
       } 
      } 
      // Get v2 providers 
      using (var regKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\_V2Providers")) 
      { 
       foreach (var subKeyName in regKey.GetSubKeyNames()) 
       { 
        using (var subKey = regKey.OpenSubKey(subKeyName)) 
        { 
         foreach (var perfKeyName in subKey.GetSubKeyNames()) 
         { 
          using (var perfKey = subKey.OpenSubKey(perfKeyName)) 
          { 
           var blah = (string) perfKey.GetValue("NeutralName"); 
           if (blah != null) 
           { 
            pcc2.Add(blah); 
           } 
          } 
         } 
        } 
       } 
      } 
      var ps = PowerShell.Create(); 

      ps.AddCommand("Get-Counter").AddParameter("listSet", "*"); 
      var pcc3 = ps.Invoke().Select(result => result.Members["CounterSetName"].Value.ToString()).ToList(); 

      pcc1.Sort(); 
      pcc2.Sort(); 
      pcc3.Sort(); 
      Console.Out.WriteLine("Getting automatically from the microsoft framework gave {0} results.", pcc1.Count()); 
      Console.Out.WriteLine("Getting manually from the registry gave {0} results.", pcc2.Count()); 
      Console.Out.WriteLine("Getting from PowerShell gave {0} results.", pcc3.Count()); 
      Console.In.ReadLine(); 
     } 
    } 
} 

在我的機器我通過使用.NET Framework,117弄138解析註冊表,以及使用PowerShell(這是正確的答案)。

但是,取決於安裝PowerShell/Windows SDK的用戶不是真正的選擇。

任何人有任何想法呢?是否有一些絕密的版本3性能計數器類別,隱藏在註冊表中的其他位置,需要追蹤?我不僅沒有想法嘗試,我已經用盡了不好的想法去嘗試。有什麼祕密的命令行開關可以在perfmon上使用,讓它列出所有的類別?

+2

我發現這個PowerShell片段'Get-Counter -listSet * | Select-Object -ExpandProperty Paths'(來源:http://blogs.msdn.com/b/powershell/archive/2009/04/21/v2-quick-tip-monitoring-performance-counters-with-powershell.aspx) 。 – 2013-04-10 11:57:54

+0

謝謝。但我需要通過編程來完成。更重要的是,我不能依賴安裝了PowerShell的最終用戶。我沒有安裝PowerShell。 :) – 2013-04-10 12:01:41

回答

1

性能計數器(和類別)按每個語言環境註冊。也就是說,根據語言的不同,您可以使用不同的名稱。

所有可用的性能類別及其計數器都在Windows註冊表中的HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib下注冊。您會找到每種可用語言的子密鑰(例如,英語爲009)。

PerformanceCounterCategory.GetCategories()方法在內部的工作原理是首先檢查「不變文化」範疇。如果它發現任何它將返回這個集合。所以,如果由於某些錯誤或供應商的監督一類是隻適用於一種語言,你會不會根據您當前語言設置(無論是操作系統或應用程序或兩者)上得到它。

我會先檢查HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\<langcode>\Counter鍵的內容,看看是否可能丟失的類別只在其中的一個。相關問題可能是this (Google search),但我沒有進一步檢查。

坦率地說,我不知道有什麼「更好」的方式來獲取可用計數器列表。如果你的問題是上面描述的問題(或相關問題),我寧願試着去弄清楚情況。

+0

這給出的結果更少。請參閱有問題的修改。 – 2013-04-11 09:18:47

2

我認爲你正在運行到什麼,我將有資格作爲Perflib發出V2櫃檯誘導一個.NET Framework錯誤。

在幕後,PerformanceCounterCategory使用Registry Functions獲取有關當前向Performance子系統註冊的類別(即對象),實例和計數器的信息。您可以通過使用ILSpy查看PerformanceCounterCategory的代碼來驗證此情況。 「核心」 -providers和「可擴展性」 -providers:

計數器可以通過兩種類型的提供者辦理登記。這些名字是我發明的,因爲缺乏更好的選擇。

睿商都建立了深厚的到Windows和接口與性能子系統緊密提供計數器,如那些流程,系統等,如果你不能夠通過PerformanceCounterCategory看到這種計數器,它很可能您的Windows安裝有一些深層問題,並且在事件日誌中至少有一些these errors。我認爲這不是你的情況。

通過所記錄的Perflib interface績效子系統可擴展性,提供接口,可提供所有其他櫃檯。要注意,對於一些Windows功能的計數器是通過可擴展的提供程序註冊,因爲是主要的微軟產品如SQL Server,.NET框架等櫃檯所以這不是重要的是,核心供應商對於一切由MS和可擴展性提出 - 第三方提供者。

如果您無法查看通過Perflib註冊的PerformanceCounterCategory計數器,首先可能是他們的提供程序在系統中配置不正確或配置已損壞。在這種情況下,你應該在你的事件記錄一些從these docs在性能計數器加載或性能庫可用性部分定義的錯誤。我認爲這不是你的情況。

第二個原因是有關Perflib商在幕後是如何工作的。要求他們的櫃檯登記需要兩個主要步驟。第一步是使用LodCtr.exe在註冊表中編寫提供程序的配置。我認爲這已經自動爲您通過您在interesed計數器的安裝完成,配置是否正確,特別是因爲如果有這種配置的問題,你可能會在事件前面提到的一些錯誤日誌。第二步是實際註冊Perflib提供者和Performance子系統。

現在我們正在接近這個問題。 Perflib v1和v2提供商的註冊完全不同。對於v1,提供程序的代碼將寫入從第一步寫入的註冊表配置引用的DLL中,並由系統自己加載。因此,Perflib v1提供程序註冊會在系統從註冊表讀取配置信息並加載DLL時自動發生。對於Perflib v2提供商來說,事情是不同的。供應商的代碼不再由系統直接執行,而是由與供應商相關的應用程序/服務執行。因此,如果您編寫的應用程序使用Perflib v2創建自定義提供程序/計數器,則您的應用程序還將運行用於爲這些提供程序收集數據的代碼,並且它將以文檔化的方式與Performance子系統進行交互。麻煩的是,現在Perflib v2提供程序在系統中註冊的代碼必須由託管提供程序代碼的應用程序觸發(而不是由系統自動爲Perflib v1觸發)。因此,例如,如果應用程序是Windows服務且服務尚未啓動,則提供程序將不會註冊到Performance子系統,並且它們的計數器通過註冊表功能/ PerformanceCounterCategory不可見(尚)。

Here是文檔的描述這種自我登記Perflib V2提供的相關部分:

你的提供商必須調用CounterInitialize和CounterCleanup功能。 CounterInitialize調用PerfStartProvider函數來註冊提供程序,並調用PerfSetCounterSetInfo函數來初始化計數器集。 CounterCleanup調用PerfStopProvider函數來刪除提供者的註冊。

結論,有兩種不同的方式列出類別,實例和計數器。一種是查詢註冊表功能並列出在查詢時註冊的所有項目。另一種方法是查看註冊表中描述的提供程序中寫入的配置信息,無論它們是否在查詢時註冊到Performance子系統。

實際上,您需要使用兩種方法的組合,因爲您只能通過查詢註冊表函數來獲取類別的實例,並且您只能通過查詢配置來獲得尚未註冊的提供程序的類別和計數器寫在註冊表中。

不幸的是,PerformanceCounterCategory僅查詢註冊表函數,因此無法獲得關於尚未註冊的Perflib v2提供程序的信息。您可以通過其他方式查看這些提供程序,例如通過性能監視器MMC(後臺使用PDH API,它可以顯示已註冊和尚未註冊的計數器組合)或typeperf.exe -qx

您可以測試上述適用於您的BranchCache類別。下面是在Win 7

  1. 測試的例子確保與顯示名稱BranchCache啓動Windows服務,然後運行此C#代碼:

    Debug.WriteLine((new PerformanceCounterCategory("BranchCache")).ReadCategory().Keys.Count); 
    

    你應該沒有寫入錯誤和21調試輸出。

  2. 現在停止BranchCache服務並再次運行C#代碼。您將收到一個異常,因爲該類別不再註冊到Performance子系統,因此PerformanceCounterCategory無法找到它。

爲了確保我描述適用於您通過PerformanceCounterCategory.GetCategories()缺少櫃檯,檢查丟失計數器由typeperf -qx與在註冊表中配置下HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\_V2Providers地方供應商相關聯的名稱類別列示。

解決方案是編寫一個C#包裝器PDH API並以這種方式獲取您的信息。這是不平凡的,特別是如果你不習慣處理本地交互。 WMI也似乎是一個有效的選項(我嘗試通過PowerShell快速列出性能對象,並且似乎返回所有提供者的計數器),但是雖然您不需要知道如何與本機代碼交互,但需要知道WMI,這也是不平凡的。