Condividi tramite


Accesso ai dati sulle prestazioni in C++

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

Le sezioni seguenti sono descritte 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 il client e il server si trovano nello stesso computer, un aggiornamento carica il provider a prestazioni elevate 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.

Anche un aggiornamento:

  • 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 non riesce. Per impedire la riconnessione, passare il flag WBEM_FLAG_REFRESH_NO_AUTO_RECONNECT nella chiamata al metodo Refresh. I client di script devono impostare la proprietà SWbemRefresher.AutoReconnect su FALSE.

  • Carica più oggetti ed enumeratori forniti dallo stesso provider o da provider diversi.

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

  • Enumera gli oggetti .

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

Al termine della scrittura del client ad alte prestazioni, potresti voler migliorare il tempo di risposta. Poiché l'interfacciaIWbemObjectAccessè 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 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 offre le migliori prestazioni complessive.

Aggiunta di enumeratori all'aggiornamento WMI

Sia il numero di istanze che i dati in ogni istanza vengono aggiornati aggiungendo un enumeratore al componente di aggiornamento in modo che ogni chiamata a IWbemRefresher::Refresh restituisca 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'interfacciaIWbemServices.

    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

Nell'esempio di codice C++ seguente viene enumerata una classe a prestazioni elevate, 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 dei contatori di prestazioni

Accesso ai dati sulle prestazioni nello script

L'aggiornamento dei dati WMI negli script

Attività WMI: Il monitoraggio delle prestazioni

Monitoraggio dei dati sulle prestazioni

Qualificatori di proprietà per le classi di contatori delle prestazioni formattati

Tipi di Contatori delle Prestazioni WMI

Wmiadap.exe

queryPerformanceCounter