다음을 통해 공유


C++에서 성능 데이터 액세스

WMI 고성능 API는 성능 카운터 클래스데이터를 가져오는 일련의 인터페이스입니다. 이러한 인터페이스는 샘플링 속도를 높이기 위해 새로 고침 개체를 사용해야 합니다. 스크립팅에서 새로 고침 개체를 사용하는 방법에 대한 자세한 내용은 스크립트 성능 데이터 액세스 WMI 작업: 성능 모니터링 참조하세요.

이 항목에서는 다음 섹션에 대해 설명합니다.

성능 데이터 새로 고침

새로 고침 개체는 프로세스 경계를 넘지 않고 데이터를 검색하여 데이터 공급자 및 클라이언트 성능을 향상합니다. 클라이언트와 서버가 모두 동일한 컴퓨터에 있는 경우 새로 고침은 고성능 공급자 in-process를 클라이언트에 로드하고 공급자 개체에서 클라이언트 개체로 직접 데이터를 복사합니다. 클라이언트와 서버가 서로 다른 컴퓨터에 있는 경우 원격 컴퓨터에서 개체를 캐싱하고 최소한의 데이터 집합을 클라이언트로 전송하여 성능을 향상합니다.

또한 새로 고침:

  • 네트워크 오류가 발생하거나 원격 컴퓨터가 다시 시작될 때 클라이언트를 원격 WMI 서비스에 자동으로 다시 연결합니다.

    기본적으로 새로 고침은 두 컴퓨터 간의 원격 연결이 실패할 때 관련 고성능 공급자에 애플리케이션을 다시 연결하려고 시도합니다. 다시 연결을 방지하려면 Refresh 메서드 호출에서 WBEM_FLAG_REFRESH_NO_AUTO_RECONNECT 플래그를 전달합니다. 스크립팅 클라이언트는 SWbemRefresher.AutoReconnect 속성을 로 false설정해야 합니다.

  • 동일하거나 다른 공급자가 제공하는 여러 개체 및 열거자를 로드합니다.

    여러 개체, 열거자 또는 둘 다를 새로 고침에 추가할 수 있습니다.

  • 개체를 열거합니다.

    다른 공급자와 마찬가지로 고성능 공급자는 개체를 열거할 수 있습니다.

고성능 클라이언트 작성을 마치면 응답 시간을 개선할 수 있습니다. IWbemObjectAccess 인터페이스는 속도에 최적화되어 있으므로 인터페이스는 본질적으로 스레드 안전하지 않습니다. 따라서 새로 고침 작업 중에 새로 고칠 수 있는 개체 또는 열거형에 액세스하지 않습니다. IWbemObjectAccess 메서드 호출 중에 스레드 간에 개체를 보호하려면 IWbemObjectAccess::LockUnlock 메서드를 사용하십시오. 성능을 향상시키려면 개별 스레드를 잠글 필요가 없도록 스레드를 동기화합니다. 스레드를 줄이고 새로 고침 작업을 위해 개체 그룹을 동기화하면 전반적인 성능이 가장 좋습니다.

WMI 리프레셔에 열거자 추가

IWbemRefresher::Refresh 호출할 때마다 완전한 열거가 수행되도록 새로 고침에 열거자를 추가하여 각 인스턴스의 인스턴스 수와 데이터를 모두 새로 고칩니다.

다음 C++ 코드 예제에서는 올바르게 컴파일하려면 다음 참조 및 #include 문이 필요합니다.

#define _WIN32_DCOM

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

다음 절차에서는 새로 고침에 열거자를 추가하는 방법을 보여줍니다.

새로 고침에 열거자를 추가하려면

  1. 새로 고칠 수 있는 개체의 경로와 IWbemServices 인터페이스를 사용하여 IWbemConfigureRefresher::AddEnum 메서드를 호출합니다.

    새로 고침은 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. 다음 작업을 수행하는 루프를 만듭니다.

예시

다음 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