Поделиться через


Доступ к данным о производительности в C++

Высокопроизводительный API WMI — это ряд интерфейсов, которые получают данные из классов счетчиков производительности . Эти интерфейсы требуют использования объекта обновления данных для увеличения частоты выборки. Дополнительные сведения об использовании объекта обновления данных в скриптах см. в разделе «Доступ к данным о производительности в скриптах» и «Задачи WMI: Мониторинг производительности».

В этом разделе рассматриваются следующие разделы:

Обновление данных о производительности

Объект обновления повышает производительность поставщика данных и клиента путем извлечения данных без пересечения границ процесса. Если клиент и сервер находятся на одном компьютере, модуль обновления загружает высокопроизводительного поставщика услуг внутри процесса клиента и копирует данные непосредственно из объектов поставщика в клиентские объекты. Если клиент и сервер находятся на разных компьютерах, средство обновления повышает производительность путем кэширования объектов на удаленном компьютере и передачи минимальных наборов данных клиенту.

Напоминание также:

  • Автоматически повторно подключает клиента к удаленной службе WMI при возникновении сетевой ошибки или перезапускается удаленный компьютер.

    По умолчанию средство обновления пытается повторно подключить приложение к соответствующему поставщику высокой производительности при сбое удаленного подключения между двумя компьютерами. Чтобы предотвратить повторное подключение, передайте флаг WBEM_FLAG_REFRESH_NO_AUTO_RECONNECT в вызове метода Refresh. Клиенты скриптов должны задать для свойства SWbemRefresher.AutoReconnect значение FALSE.

  • Загружает несколько объектов и перечислителей, предоставляемых одинаковыми или разными поставщиками.

    Позволяет добавлять в обновитель несколько объектов, перечислителей или и то, и другое.

  • Перечисляет объекты.

    Как и другие поставщики, поставщик высокой производительности может перечислять объекты.

После завершения написания высокопроизводительного клиента может потребоваться улучшить время отклика. Так как интерфейс IWbemObjectAccess оптимизирован для скорости, интерфейс не является по своей природе потокобезопасным. Поэтому во время операции обновления не обращаются к обновляемому объекту или перечислению. Чтобы защитить объекты между потоками во время вызовов метода IWbemObjectAccess , используйте методы IWbemObjectAccess::Lock и Unlock. Для повышения производительности синхронизируйте потоки, чтобы не нужно блокировать отдельные потоки. Сокращение потоков и синхронизация групп объектов для операций обновления обеспечивает лучшую общую производительность.

Добавление перечислителей в средство обновления WMI

Количество экземпляров и данные в каждом экземпляре обновляются путем добавления перечислителя в средство обновления, чтобы каждый вызов IWbemRefresher::Refresh приводит к полному перечислению.

Для компиляции следующего примера кода C++ корректно необходимы следующие зависимости и #include директивы.

#define _WIN32_DCOM

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

В следующей процедуре показано, как добавить перечислитель в средство обновления.

Чтобы добавить перечислитель в обновляющий модуль

  1. Вызовите метод IWbemConfigureRefresher::AddEnum с помощью пути к обновляемому объекту и интерфейсу IWbemServices.

    Средство обновления возвращает указатель на интерфейс IWbemHiPerfEnum. Интерфейс IWbemHiPerfEnum можно использовать для доступа к объектам в перечислении.

    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. Создайте цикл, выполняющий следующие действия:

    • Обновляет объект с помощью вызова IWbemRefresher::Refresh.

    • Предоставляет массив указателей интерфейса IWbemObjectAccess для метода IWbemHiPerfEnum::GetObjects.

    • Обращается к свойствам перечислителя с помощью методов IWbemObjectAccess, передаваемых в GetObjects.

      Дескриптор свойств можно передать каждому экземпляру IWbemObjectAccess, чтобы получить обновленное значение. Клиент должен вызвать Release, чтобы освободить указатели IWbemObjectAccess, возвращаемые GetObjects.

Пример

В следующем примере кода C++ перечисляется высокопроизводительный класс, где клиент извлекает дескриптор свойств из первого объекта и повторно использует дескриптор для остальной части операции обновления. Каждый вызов метода Refresh обновляет количество экземпляров и данных экземпляра.

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

Классы счетчиков производительности

Доступ к данным о производительности в сценарии

Обновление данных WMI в скриптах

задачи WMI : мониторинг производительности

мониторинг данных о производительности

Квалификаторы свойств для классов форматированных счетчиков производительности

Типы счетчиков производительности WMI

Wmiadap.exe

QueryPerformanceCounter