Share via


Zugreifen auf Leistungsdaten in C++

Die WMI-Hochleistungs-API besteht aus einer Reihe von Schnittstellen, die Daten aus Leistungsindikatorklassen abrufen. Diese Schnittstellen erfordern die Verwendung eines Aktualisierungsobjekts, um die Samplingrate zu erhöhen. Weitere Informationen zur Verwendung des Aktualisierungsobjekts in Skripts finden Sie unter Zugreifen auf Leistungsdaten in Skript und WMI-Aufgaben: Leistungsüberwachung.

In diesem Themenbereich werden die folgenden Abschnitte behandelt:

Aktualisieren von Leistungsdaten

Ein Aktualisierungsobjekt erhöht die Leistung des Datenanbieters und des Clients, indem Daten abgerufen werden, ohne Prozessgrenzen zu überschreiten. Wenn sich sowohl der Client als auch der Server auf demselben Computer befinden, lädt eine Aktualisierung den Hochleistungsanbieter im Prozess auf den Client und kopiert Daten direkt aus Anbieterobjekten in Clientobjekte. Wenn sich der Client und der Server auf unterschiedlichen Computern befinden, erhöht die Aktualisierung die Leistung, indem Objekte auf dem Remotecomputer zwischengespeichert und minimale Datasets an den Client übertragen werden.

Ein Aktualisierungsobjekt führt außerdem Folgendes durch:

  • Verbindet einen Client automatisch wieder mit einem WMI-Remotedienst, wenn ein Netzwerkfehler auftritt oder der Remotecomputer neu gestartet wird.

    Standardmäßig versucht eine Aktualisierung, Ihre Anwendung erneut mit dem relevanten Hochleistungsanbieter zu verbinden, wenn eine Remoteverbindung zwischen den beiden Computern fehlschlägt. Um die erneute Verbindung zu verhindern, übergeben Sie das Flag WBEM_FLAG_REFRESH_NO_AUTO_RECONNECT im Methodenaufruf Refresh . Skriptclients müssen die Eigenschaft SWbemRefresher.AutoReconnect auf FALSE festlegen.

  • Lädt mehrere Objekte und Enumeratoren, die von demselben oder verschiedenen Anbietern bereitgestellt werden.

    Ermöglicht das Hinzufügen mehrerer Objekte, Enumeratoren oder beides zu einer Aktualisierung.

  • Listet Objekte auf.

    Wie andere Anbieter kann ein Hochleistungsanbieter Objekte auflisten.

Nachdem Sie mit dem Schreiben Ihres Hochleistungsclients fertig sind, möchten Sie möglicherweise Ihre Antwortzeit verbessern. Da die Schnittstelle IWbemObjectAccess für die Geschwindigkeit optimiert ist, ist die Schnittstelle nicht intrinsisch threadsicher. Greifen Sie daher während eines Aktualisierungsvorgangs nicht auf das aktualisierbare Objekt oder die Enumeration zu. Verwenden Sie zum Threadübergreifenden Schutz von Objekten während Methodenaufrufen IWbemObjectAccess die Methoden IWbemObjectAccess::Lock und Unlock . Um die Leistung zu verbessern, synchronisieren Sie Ihre Threads, sodass Sie einzelne Threads nicht sperren müssen. Das Reduzieren von Threads und das Synchronisieren von Objektgruppen für Aktualisierungsvorgänge bietet die beste Gesamtleistung.

Hinzufügen von Enumeratoren zur WMI-Aktualisierung

Sowohl die Anzahl der Instanzen als auch die Daten in den einzelnen Instanz werden aktualisiert, indem der Aktualisierung ein Enumerator hinzugefügt wird, sodass jeder Aufruf von IWbemRefresher::Refresh zu einer vollständigen Enumeration führt.

Das folgende C++-Codebeispiel erfordert die folgenden Verweise und #include-Anweisungen für eine ordnungsgemäße Kompilierung.

#define _WIN32_DCOM

#include <iostream>
using namespace std;
#include <Wbemidl.h>
#pragma comment(lib, "wbemuuid.lib")

Das folgende Verfahren zeigt, wie Sie einer Aktualisierung einen Enumerator hinzufügen.

So fügen Sie einem Aktualisierungsobjekt einen Enumerator hinzu

  1. Rufen Sie die Methode IWbemConfigureRefresher::AddEnum auf, indem Sie den Pfad zum aktualisierbaren Objekt und die Schnittstelle IWbemServices verwenden.

    Die Aktualisierung gibt einen Zeiger auf eine Schnittstelle IWbemHiPerfEnum zurück. Sie können die Schnittstelle IWbemHiPerfEnum verwenden, um auf die Objekte in der Enumeration zuzugreifen.

    IWbemHiPerfEnum* pEnum = NULL;
    long lID;
    IWbemConfigureRefresher* pConfig;
    IWbemServices* pNameSpace;
    
    // Add an enumerator to the refresher.
    if (FAILED (hr = pConfig->AddEnum(
        pNameSpace, 
        L"Win32_PerfRawData_PerfProc_Process", 
        0, 
        NULL,
        &pEnum, 
        &lID)))
    {
        goto CLEANUP;
    }
    pConfig->Release();
    pConfig = NULL;
    
  2. Erstellen Sie eine Schleife, die die folgenden Aktionen ausführt:

Beispiel

Im folgenden C++-Codebeispiel wird eine Hochleistungsklasse aufgelistet, bei der der Client ein Eigenschaftenhandle aus dem ersten Objekt abruft und das Handle für den Rest des Aktualisierungsvorgangs wiederverwendet. Bei jedem Aufruf der Methode Refresh werden die Anzahl der Instanzen und die Instanzdaten aktualisiert.

#define _WIN32_DCOM

#include <iostream>
using namespace std;
#include <Wbemidl.h>

#pragma comment(lib, "wbemuuid.lib")

int __cdecl wmain(int argc, wchar_t* argv[])
{
    // To add error checking,
    // check returned HRESULT below where collected.
    HRESULT                 hr = S_OK;
    IWbemRefresher          *pRefresher = NULL;
    IWbemConfigureRefresher *pConfig = NULL;
    IWbemHiPerfEnum         *pEnum = NULL;
    IWbemServices           *pNameSpace = NULL;
    IWbemLocator            *pWbemLocator = NULL;
    IWbemObjectAccess       **apEnumAccess = NULL;
    BSTR                    bstrNameSpace = NULL;
    long                    lID = 0;
    long                    lVirtualBytesHandle = 0;
    long                    lIDProcessHandle = 0;
    DWORD                   dwVirtualBytes = 0;
    DWORD                   dwProcessId = 0;
    DWORD                   dwNumObjects = 0;
    DWORD                   dwNumReturned = 0;
    DWORD                   dwIDProcess = 0;
    DWORD                   i=0;
    int                     x=0;

    if (FAILED (hr = CoInitializeEx(NULL,COINIT_MULTITHREADED)))
    {
        goto CLEANUP;
    }

    if (FAILED (hr = CoInitializeSecurity(
        NULL,
        -1,
        NULL,
        NULL,
        RPC_C_AUTHN_LEVEL_NONE,
        RPC_C_IMP_LEVEL_IMPERSONATE,
        NULL, EOAC_NONE, 0)))
    {
        goto CLEANUP;
    }

    if (FAILED (hr = CoCreateInstance(
        CLSID_WbemLocator, 
        NULL,
        CLSCTX_INPROC_SERVER,
        IID_IWbemLocator,
        (void**) &pWbemLocator)))
    {
        goto CLEANUP;
    }

    // Connect to the desired namespace.
    bstrNameSpace = SysAllocString(L"\\\\.\\root\\cimv2");
    if (NULL == bstrNameSpace)
    {
        hr = E_OUTOFMEMORY;
        goto CLEANUP;
    }
    if (FAILED (hr = pWbemLocator->ConnectServer(
        bstrNameSpace,
        NULL, // User name
        NULL, // Password
        NULL, // Locale
        0L,   // Security flags
        NULL, // Authority
        NULL, // Wbem context
        &pNameSpace)))
    {
        goto CLEANUP;
    }
    pWbemLocator->Release();
    pWbemLocator=NULL;
    SysFreeString(bstrNameSpace);
    bstrNameSpace = NULL;

    if (FAILED (hr = CoCreateInstance(
        CLSID_WbemRefresher,
        NULL,
        CLSCTX_INPROC_SERVER,
        IID_IWbemRefresher, 
        (void**) &pRefresher)))
    {
        goto CLEANUP;
    }

    if (FAILED (hr = pRefresher->QueryInterface(
        IID_IWbemConfigureRefresher,
        (void **)&pConfig)))
    {
        goto CLEANUP;
    }

    // Add an enumerator to the refresher.
    if (FAILED (hr = pConfig->AddEnum(
        pNameSpace, 
        L"Win32_PerfRawData_PerfProc_Process", 
        0, 
        NULL, 
        &pEnum, 
        &lID)))
    {
        goto CLEANUP;
    }
    pConfig->Release();
    pConfig = NULL;

    // Get a property handle for the VirtualBytes property.

    // Refresh the object ten times and retrieve the value.
    for(x = 0; x < 10; x++)
    {
        dwNumReturned = 0;
        dwIDProcess = 0;
        dwNumObjects = 0;

        if (FAILED (hr =pRefresher->Refresh(0L)))
        {
            goto CLEANUP;
        }

        hr = pEnum->GetObjects(0L, 
            dwNumObjects, 
            apEnumAccess, 
            &dwNumReturned);
        // If the buffer was not big enough,
        // allocate a bigger buffer and retry.
        if (hr == WBEM_E_BUFFER_TOO_SMALL 
            && dwNumReturned > dwNumObjects)
        {
            apEnumAccess = new IWbemObjectAccess*[dwNumReturned];
            if (NULL == apEnumAccess)
            {
                hr = E_OUTOFMEMORY;
                goto CLEANUP;
            }
            SecureZeroMemory(apEnumAccess,
                dwNumReturned*sizeof(IWbemObjectAccess*));
            dwNumObjects = dwNumReturned;

            if (FAILED (hr = pEnum->GetObjects(0L, 
                dwNumObjects, 
                apEnumAccess, 
                &dwNumReturned)))
            {
                goto CLEANUP;
            }
        }
        else
        {
            if (hr == WBEM_S_NO_ERROR)
            {
                hr = WBEM_E_NOT_FOUND;
                goto CLEANUP;
            }
        }

        // First time through, get the handles.
        if (0 == x)
        {
            CIMTYPE VirtualBytesType;
            CIMTYPE ProcessHandleType;
            if (FAILED (hr = apEnumAccess[0]->GetPropertyHandle(
                L"VirtualBytes",
                &VirtualBytesType,
                &lVirtualBytesHandle)))
            {
                goto CLEANUP;
            }
            if (FAILED (hr = apEnumAccess[0]->GetPropertyHandle(
                L"IDProcess",
                &ProcessHandleType,
                &lIDProcessHandle)))
            {
                goto CLEANUP;
            }
        }
           
        for (i = 0; i < dwNumReturned; i++)
        {
            if (FAILED (hr = apEnumAccess[i]->ReadDWORD(
                lVirtualBytesHandle,
                &dwVirtualBytes)))
            {
                goto CLEANUP;
            }
            if (FAILED (hr = apEnumAccess[i]->ReadDWORD(
                lIDProcessHandle,
                &dwIDProcess)))
            {
                goto CLEANUP;
            }

            wprintf(L"Process ID %lu is using %lu bytes\n",
                dwIDProcess, dwVirtualBytes);

            // Done with the object
            apEnumAccess[i]->Release();
            apEnumAccess[i] = NULL;
        }

        if (NULL != apEnumAccess)
        {
            delete [] apEnumAccess;
            apEnumAccess = NULL;
        }

       // Sleep for a second.
       Sleep(1000);
    }
    // exit loop here
    CLEANUP:

    if (NULL != bstrNameSpace)
    {
        SysFreeString(bstrNameSpace);
    }

    if (NULL != apEnumAccess)
    {
        for (i = 0; i < dwNumReturned; i++)
        {
            if (apEnumAccess[i] != NULL)
            {
                apEnumAccess[i]->Release();
                apEnumAccess[i] = NULL;
            }
        }
        delete [] apEnumAccess;
    }
    if (NULL != pWbemLocator)
    {
        pWbemLocator->Release();
    }
    if (NULL != pNameSpace)
    {
        pNameSpace->Release();
    }
    if (NULL != pEnum)
    {
        pEnum->Release();
    }
    if (NULL != pConfig)
    {
        pConfig->Release();
    }
    if (NULL != pRefresher)
    {
        pRefresher->Release();
    }

    CoUninitialize();

    if (FAILED (hr))
    {
        wprintf (L"Error status=%08x\n",hr);
    }

    return 1;
}

Leistungsindikatorklassen

Zugreifen auf Leistungsdaten im Skript

Aktualisieren von WMI-Daten in Skripts

WMI-Aufgaben: Leistungsüberwachung

Überwachen von Leistungsdaten

Eigenschaftenqualifizierer für formatierte Leistungsklassen

WMI-Leistungsindikatortypen

Wmiadap.exe

QueryPerformanceCounter