Acceso a datos de rendimiento en C++

La API de alto rendimiento de WMI es una serie de interfaces que obtienen datos de clases de contador de rendimiento. Estas interfaces requieren el uso de un objeto refresher para aumentar la frecuencia de muestreo. Para más información sobre el uso del objeto refresher en el scripting, consulte Acceso a datos de rendimiento en scripts y Tareas de WMI: Supervisión del rendimiento.

En este tema se describen las secciones siguientes:

Recuperación de datos de rendimiento

Un objeto refresher aumenta el rendimiento del proveedor de datos y el cliente mediante la recuperación de datos sin cruzar los límites del proceso. Si el cliente y el servidor se encuentran en el mismo equipo, un actualizador carga el proveedor de alto rendimiento en proceso en el cliente y copia los datos directamente desde los objetos de proveedor en los objetos de cliente. Si el cliente y el servidor se encuentran en equipos diferentes, el actualizador aumenta el rendimiento mediante el almacenamiento en caché de objetos en el equipo remoto y la transmisión del mínimo de conjuntos de datos al cliente.

Un actualizador también:

  • Vuelve a conectar automáticamente un cliente a un servicio WMI remoto cuando se produce un error de red o se reinicia el equipo remoto.

    De forma predeterminada, un actualizador intenta volver a conectar la aplicación al proveedor de alto rendimiento pertinente si se produce un error en una conexión remota entre los dos equipos. Para evitar la reconexión, pase la marca WBEM_FLAG_REFRESH_NO_AUTO_RECONNECT en la llamada al método Refresh. Los clientes de scripting deben establecer la propiedad SWbemRefresher.AutoReconnect en FALSE.

  • Carga varios objetos y enumeradores proporcionados por los mismos proveedores u otros diferentes.

    Permite agregar varios objetos, enumeradores o ambos a un actualizador.

  • Enumera objetos.

    Al igual que otros proveedores, un proveedor de alto rendimiento puede enumerar objetos.

Después de terminar de escribir el cliente de alto rendimiento, es posible que desee mejorar el tiempo de respuesta. Dado que la interfaz IWbemObjectAccess está optimizada para obtener velocidad, la interfaz no es intrínsecamente segura para subprocesos. Por lo tanto, durante una operación de actualización, no acceda al objeto actualizable ni a la enumeración. Para proteger objetos entre subprocesos durante las llamadas al método IWbemObjectAccess, use los métodos IWbemObjectAccess::Lock y Unlock. Para mejorar el rendimiento, sincronice los subprocesos para que no sea necesario bloquear subprocesos individuales. Reducir los subprocesos y sincronizar grupos de objetos para las operaciones de actualización proporciona el mejor rendimiento general.

Adición de enumeradores al actualizador de WMI

Tanto el número de instancias como los datos de cada instancia se actualizan agregando un enumerador al actualizador para que cada llamada a IWbemRefresher::Refresh tenga como resultado una enumeración completa.

El ejemplo de código de C++ siguiente requiere las siguientes referencias e instrucciones #include para compilarse correctamente.

#define _WIN32_DCOM

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

En el procedimiento siguiente se muestra cómo agregar un enumerador a un actualizador.

Para agregar un enumerador a un actualizador

  1. Llame al método IWbemConfigureRefresher::AddEnum mediante la ruta de acceso al objeto actualizable y a la interfaz IWbemServices.

    El actualizador devuelve un puntero a una interfaz IWbemHiPerfEnum. Puede usar la interfaz IWbemHiPerfEnum para acceder a los objetos de la enumeración.

    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. Cree un bucle que realice las siguientes acciones:

Ejemplo

El siguiente ejemplo de código de C++ enumera una clase de alto rendimiento en la que el cliente recupera un identificador de propiedad del primer objeto y reutiliza el identificador para el resto de la operación de actualización. Cada llamada al método Refresh actualiza el número de instancias y los datos de la instancia.

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

Clases de contador de rendimiento

Acceso a datos de rendimiento en scripts

Actualización de datos de WMI en scripts

Tareas de WMI: Supervisión del rendimiento

Supervisión de datos de rendimiento

Calificadores de propiedades para clases de contador de rendimiento con formato

Tipos de contador de rendimiento de WMI

Wmiadap.exe

QueryPerformanceCounter