Partilhar via


Acessando dados de desempenho em C++

A API de alto desempenho WMI é uma série de interfaces que obtêm dados de classes de contador de desempenho. Essas interfaces exigem o uso de um objeto refresher para aumentar a taxa de amostragem. Para obter mais informações sobre como usar o objeto refresher em scripts, consulte Acessando dados de desempenho no Script e Tarefas WMI: Monitoramento de desempenho.

As seguintes seções são discutidas neste tópico:

Atualizando dados de desempenho

Um objeto de atualização aumenta o desempenho do provedor de dados e do cliente recuperando dados sem cruzar os limites do processo. Se o cliente e o servidor estiverem localizados no mesmo computador, uma atualização carregará o provedor de alto desempenho em processo para o cliente e copiará dados diretamente dos objetos do provedor para os objetos do cliente. Se o cliente e o servidor estiverem localizados em computadores diferentes, a atualização aumentará o desempenho armazenando objetos em cache no computador remoto e transmitindo conjuntos de dados mínimos para o cliente.

Uma atualização também:

  • Reconecta automaticamente um cliente a um serviço WMI remoto quando ocorre um erro de rede ou o computador remoto é reiniciado.

    Por padrão, uma atualização tenta reconectar seu aplicativo ao provedor de alto desempenho relevante quando uma conexão remota entre os dois computadores falha. Para evitar a reconexão, passe o sinalizador WBEM_FLAG_REFRESH_NO_AUTO_RECONNECT na chamada do método Refresh. Os clientes de script devem definir a propriedade SWbemRefresher.AutoReconnectcomo FALSE.

  • Carrega vários objetos e enumeradores fornecidos pelo mesmo provedor ou por provedores diferentes.

    Permite adicionar vários objetos, enumeradores ou ambos a uma atualização.

  • Enumera objetos.

    Como outros provedores, um provedor de alto desempenho pode enumerar objetos.

Depois de terminar de escrever seu cliente de alto desempenho, você pode querer melhorar seu tempo de resposta. Como a interface IWbemObjectAccess é otimizada para velocidade, a interface não é intrinsecamente segura para threads. Portanto, durante uma operação de atualização, não acesse o objeto atualizável ou a enumeração. Para proteger objetos entre threads durante chamadas do método IWbemObjectAccess, use os métodos IWbemObjectAccess::Lock e Unlock. Para melhorar o desempenho, sincronize seus threads para que você não precise bloquear threads individuais. A redução de threads e a sincronização de grupos de objetos para operações de atualização proporcionam o melhor desempenho geral.

Adicionando enumeradores ao atualizador do WMI

O número de instâncias e os dados em cada instância são atualizados adicionando um enumerador ao atualizador para que cada chamada para IWbemRefresher::Refresh resulte em uma enumeração completa.

O exemplo de código C++ a seguir requer as seguintes referências e instruções #include para compilar corretamente.

#define _WIN32_DCOM

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

O procedimento a seguir mostra como adicionar um enumerador a uma atualização.

Para adicionar um enumerador a um atualizador

  1. Chame o método de IWbemConfigureRefresher::AddEnum usando o caminho para o objeto atualizável e a interfaceIWbemServices.

    O atualizador retorna um ponteiro para uma interface IWbemHiPerfEnum. Você pode usar a interface IWbemHiPerfEnum para acessar os objetos na enumeração.

    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. Crie um loop que execute as seguintes ações:

Exemplo

O exemplo de código C++ a seguir enumera uma classe de alto desempenho, onde o cliente recupera um identificador de propriedade do primeiro objeto e reutiliza o identificador para o restante da operação de atualização. Cada chamada para o método Refresh atualiza o número de instâncias e os dados da instância.

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

Classes de Contadores de Desempenho

Acessando dados de desempenho no Script

Atualização de dados WMI em scripts

Tarefas WMI: Monitoramento de desempenho

Monitoramento de dados de desempenho

Qualificadores de Propriedade para Classes de Contadores de Desempenho Formatadas

Tipos de Contador de Desempenho WMI

Wmiadap.exe

QueryPerformanceCounter