Accesso ai dati sulle prestazioni in C++

L'API WMI ad alte prestazioni è una serie di interfacce che ottengono dati da classi di contatori delle prestazioni. Queste interfacce richiedono l'uso di un oggetto aggiornatore per aumentare la frequenza di campionamento. Per altre informazioni sull'uso dell'oggetto refresher nello scripting, vedere Accesso ai dati sulle prestazioni nelle attività script e WMI: Monitoraggio delle prestazioni.

Le sezioni seguenti sono illustrate in questo argomento:

Aggiornamento dei dati sulle prestazioni

Un oggetto refresher aumenta le prestazioni del provider di dati e del client recuperando i dati senza superare i limiti del processo. Se sia il client che il server si trovano nello stesso computer, un aggiornamento carica il provider ad alte prestazioni nel client e copia i dati direttamente dagli oggetti provider negli oggetti client. Se il client e il server si trovano in computer diversi, l'aggiornamento aumenta le prestazioni memorizzando nella cache gli oggetti nel computer remoto e trasmettendo set di dati minimi al client.

Un aggiornamento anche:

  • Riconnette automaticamente un client a un servizio WMI remoto quando si verifica un errore di rete o il computer remoto viene riavviato.

    Per impostazione predefinita, un aggiornamento tenta di riconnettere l'applicazione al provider ad alte prestazioni pertinente quando una connessione remota tra i due computer ha esito negativo. Per impedire la riconnessione, passare il flag WBEM_FLAG_REFRESH_NO_AUTO_RECONNECT nella chiamata al metodo Refresh . I client di scripting devono impostare la proprietà SWbemRefresher.AutoReconnect su FALSE.

  • Carica più oggetti e enumeratori forniti dagli stessi provider o diversi.

    Consente di aggiungere più oggetti, enumeratori o entrambi a un aggiornamento.

  • Enumera oggetti.

    Come altri provider, un provider ad alte prestazioni può enumerare oggetti.

Al termine della scrittura del client ad alte prestazioni, è possibile migliorare il tempo di risposta. Poiché l'interfaccia IWbemObjectAccess è ottimizzata per la velocità, l'interfaccia non è intrinsecamente threadsafe. Pertanto, durante un'operazione di aggiornamento, non accedere all'oggetto aggiornabile o all'enumerazione. Per proteggere gli oggetti tra thread durante le chiamate al metodo IWbemObjectAccess, usare i metodi IWbemObjectAccess::Lock e Unlock. Per migliorare le prestazioni, sincronizzare i thread in modo che non sia necessario bloccare singoli thread. La riduzione dei thread e la sincronizzazione di gruppi di oggetti per le operazioni di aggiornamento offrono le migliori prestazioni complessive.

Aggiunta di enumeratori al aggiornatore WMI

Sia il numero di istanze che i dati in ogni istanza vengono aggiornati aggiungendo un enumeratore al aggiornatore in modo che ogni chiamata a IWbemRefresher::Refresh risultati in un'enumerazione completa.

Nell'esempio di codice C++ seguente sono necessari i riferimenti seguenti e le istruzioni #include per la compilazione corretta.

#define _WIN32_DCOM

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

La procedura seguente illustra come aggiungere un enumeratore a un aggiornamento.

Per aggiungere un enumeratore a un aggiornamento

  1. Chiamare il metodo IWbemConfigureRefresher::AddEnum usando il percorso dell'oggetto aggiornabile e l'interfaccia IWbemServices .

    L'aggiornamento restituisce un puntatore a un'interfaccia IWbemHiPerfEnum . È possibile usare l'interfaccia IWbemHiPerfEnum per accedere agli oggetti nell'enumerazione.

    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. Creare un ciclo che esegue le azioni seguenti:

Esempio

L'esempio di codice C++ seguente enumera una classe ad alte prestazioni, in cui il client recupera un handle di proprietà dal primo oggetto e riutilizza l'handle per il resto dell'operazione di aggiornamento. Ogni chiamata al metodo Refresh aggiorna il numero di istanze e i dati dell'istanza.

#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;
}

Classi di contatori delle prestazioni

Accesso ai dati sulle prestazioni nello script

Aggiornamento dei dati WMI negli script

Attività WMI: Monitoraggio delle prestazioni

Monitoraggio dei dati sulle prestazioni

Qualificatori delle proprietà per classi di contatori delle prestazioni formattate

Tipi di contatore delle prestazioni WMI

Wmiadap.exe

Queryperformancecounter