2015-11-19 31 views
5

Ich möchte die „Prozessorzeit%“ Zähler in einer Anwendung den Zugriff auf die mit verschiedenen Lokalisierungen auf Systemen läuft.Get Performance von Index

so zu tun, ich will durch seinen Index der Zähler zuzugreifen, die (siehe https://support.microsoft.com/en-us/kb/287159) einzigartig sein garantiert.

Der folgende Code funktioniert und gibt mir das richtige Ergebnis für die aktuellen locale, aber die Leistung Zähler zu öffnen Ich brauche auch den Kategorienamen des Zählers (siehe Konstrukteuren für die PerformanceCounter Klasse) sowie den Instanznamen:

[DllImport("pdh.dll", SetLastError = true, CharSet = CharSet.Unicode)] 
internal static extern UInt32 PdhLookupPerfNameByIndex(string szMachineName, uint dwNameIndex, StringBuilder szNameBuffer, ref uint pcchNameBufferSize); 

void Main() 
{ 
    var buffer = new StringBuilder(1024); 
    var bufSize = (uint)buffer.Capacity; 
    PdhLookupPerfNameByIndex(null, 6, buffer, ref bufSize); 
    Console.WriteLine(buffer.ToString()); 

    var counter = new PerformanceCounter(/* category??? */, buffer.ToString(), /* instance??? */); 
} 

Wie kann ich diese Kategorie und Instanznamen bekommen?

Siehe auch: Retrieve performance counter value in a language-independent way, die das gleiche Problem beschreibt, aber keine Lösung bietet.

Antwort

6

Sie missverstehen, wie PdhLookupPerfNameByIndex() funktioniert. Seine Aufgabe ist es einen Leistungsindikator abzubilden, sondern eine Zeichenfolge abzubilden. Es sollte sowohl für die Kategorie des Counters als auch für seinen Namen verwendet werden. Nicht für die Instanz des Counters, falls zutreffend, ist sie nicht lokalisiert.

Der beste Weg, um zu sehen, was es ist, tut von Regedit.exe verwenden. Navigieren Sie zu HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Windows NT \ Currentversion \ Perflib. Beachten Sie den "009" Schlüssel, sein Counter-Wert hat den Index zu englischem Zeichenfolgenzuordnung. Doppelklicken Sie auf Counter und kopieren Sie den Inhalt der Box in einen Texteditor, um ihn besser sehen zu können. Der Schlüssel "CurrentLanguage" ist dasselbe Mapping, verwendet aber die lokalisierten Namen.

Damit PdhLookupPerfNameByIndex() den Schlüssel CurrentLanguage verwendet, verwenden Sie die Liste, die Sie im vorherigen Schritt erhalten haben, um die Indexnummer der Zeichenfolge zu kennen. Die andere Möglichkeit, es (wie zu vermerken) unten im KB-Artikel zu tun, besteht darin, zunächst die Indexnummer aus dem Registrierungsschlüssel "009" nachzuschlagen. Auf diese Weise können Sie von der englischen Zeichenfolge in die lokalisierte Zeichenfolge umwandeln. Beachten Sie, dass der KB-Artikel den Speicherort des Registrierungsschlüssels falsch dokumentiert, keine Ahnung warum. Beachten Sie, dass es weniger als perfekt ist, wie im KB-Artikel ausgeführt, diese Zuordnungen existieren nur für die "Basis" -Zähler und der "009" -Schlüssel ist mehrdeutig, da einige Indizes auf die gleiche Zeichenfolge abgebildet werden. Das Testen auf einer lokalisierten Windows-Version ist sehr wichtig.

einige Code, der es in beide Richtungen funktioniert:

using System; 
using System.Collections.Generic; 
using System.Text; 
using Microsoft.Win32; 
using System.Diagnostics; 
using System.Runtime.InteropServices; 

public static class PerfMapper { 
    private static Dictionary<string, int> English; 
    private static Dictionary<int, string> Localized; 

    public static PerformanceCounter FromEnglish(string category, string name, string instance = null) { 
     return new PerformanceCounter(Map(category), Map(name), instance); 
    } 

    public static PerformanceCounter FromIndices(int category, int name, string instance = null) { 
     return new PerformanceCounter(PdhMap(category), PdhMap(name), instance); 
    } 

    public static bool HasName(string name) { 
     if (English == null) LoadNames(); 
     if (!English.ContainsKey(name)) return false; 
     var index = English[name]; 
     return !Localized.ContainsKey(index); 
    } 

    public static string Map(string text) { 
     if (HasName(text)) return Localized[English[text]]; 
     else return text; 
    } 

    private static string PdhMap(int index) { 
     int size = 0; 
     uint ret = PdhLookupPerfNameByIndex(null, index, null, ref size); 
     if (ret == 0x800007D2) { 
      var buffer = new StringBuilder(size); 
      ret = PdhLookupPerfNameByIndex(null, index, buffer, ref size); 
      if (ret == 0) return buffer.ToString(); 
     } 
     throw new System.ComponentModel.Win32Exception((int)ret, "PDH lookup failed"); 
    } 

    private static void LoadNames() { 
     string[] english; 
     string[] local; 
     // Retrieve English and localized strings 
     using (var hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64)) { 
      using (var key = hklm.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009")) { 
       english = (string[])key.GetValue("Counter"); 
      } 
      using (var key = hklm.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\CurrentLanguage")) { 
       local = (string[])key.GetValue("Counter"); 
      } 
     } 
     // Create English lookup table 
     English = new Dictionary<string, int>(english.Length/2, StringComparer.InvariantCultureIgnoreCase); 
     for (int ix = 0; ix < english.Length - 1; ix += 2) { 
      int index = int.Parse(english[ix]); 
      if (!English.ContainsKey(english[ix + 1])) English.Add(english[ix + 1], index); 
     } 
     // Create localized lookup table 
     Localized = new Dictionary<int, string>(local.Length/2); 
     for (int ix = 0; ix < local.Length - 1; ix += 2) { 
      int index = int.Parse(local[ix]); 
      Localized.Add(index, local[ix + 1]); 
     } 
    } 

    [DllImport("pdh.dll", CharSet = CharSet.Auto)] 
    private static extern uint PdhLookupPerfNameByIndex(string machine, int index, StringBuilder buffer, ref int bufsize); 
} 

Verwendungsbeispiel:

class Program { 
    static void Main(string[] args) { 
     var ctr1 = PerfMapper.FromEnglish("Processor", "% Processor Time"); 
     var ctr2 = PerfMapper.FromIndices(238, 6); 
    } 
} 

ich nur Zugriff auf eine englische Version von Windows haben so nicht für Genauigkeit auf einer lokalisierten Version bürgen . Bitte korrigieren Sie eventuelle Fehler, indem Sie diesen Beitrag bearbeiten.

0

Versuchen Sie dieses:

var counter = new PerformanceCounter("Processor", "% Processor Time", "_Total"); 

Es ist für mich auf dem PC mit Deutsch Lokalisierung funktioniert.

UPDATE

Dies ist ein Beispiel, Sie zu verstehen nutzen könnten, wie diese Kategorien, Instanzen und Zähler organisiert sind. Vergessen Sie nicht, Performance Monitor unter Verwaltung im Bedienfeld zu überprüfen, wo Sie einen Zähler hinzufügen oder bestehende Zähler finden.

string counterName = buffer.ToString(); 
PerformanceCounter counter = null;    
foreach (var category in PerformanceCounterCategory.GetCategories()) 
{ 
    // Get all possible instances for the current category 
    var instanceNames = category.GetInstanceNames(); 
    if (instanceNames.Length == 0) 
     continue; 
    // Get all counters in the category. 
    // We want to find an instance with underscores first, for example, "_Total"    
    var counters = category.GetCounters(
     category.GetInstanceNames().OrderBy(i => i).First()); 
    foreach (var currentCounter in counters) 
    {           
     if (currentCounter.CounterName == counterName) 
     { 
      // Hurray! Here it is! 
      counter = currentCounter; 
     } 
    } 
} 
+0

Es scheint, dass die englischen Namen die meiste Zeit funktionieren (auch auf deutschen Systemen getestet). Aber wir hatten einige Schweizer Systeme, die diese englischen Zähler nicht finden konnten. – thomai