使用 C++ 访问性能数据
WMI 高性能 API 是一系列接口,可从性能计数器类获取数据。 这些接口需要使用 refresher 对象来提高采样率。 有关在脚本中使用刷新器对象的详细信息,请参阅在脚本中访问性能数据和 WMI 任务:性能监视。
本主题包括以下部分:
刷新性能数据
刷新器对象可在不跨越进程边界的情况下检索数据,以此来提高数据提供程序和客户端性能。 如果客户端和服务器都位于同一台计算机上,则刷新器会将进程中的高性能提供程序加载到客户端,并将提供程序对象中的数据直接复制到客户端对象中。 如果客户端和服务器位于不同的计算机上,则刷新器会在远程计算机上缓存对象并将最少的数据集传输到客户端,以此来提高性能。
刷新器还具备以下功能:
发生网络错误或远程计算机重新启动时,自动将客户端重新连接到远程 WMI 服务。
默认情况下,当两台计算机之间的远程连接失败时,刷新器会尝试将应用程序重新连接到相关的高性能提供程序。 若要阻止重新连接,请在 Refresh 方法调用中传递 WBEM_FLAG_REFRESH_NO_AUTO_RECONNECT 标志。 脚本客户端必须将 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")
以下过程演示如何向刷新器添加枚举程序。
将枚举器添加到刷新器
使用可刷新对象的路径和 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;
创建执行以下操作的循环:
通过调用 IWbemRefresher::Refresh 来刷新对象。
提供指向 IWbemHiPerfEnum::GetObjects 方法的 IWbemObjectAccess 接口指针的数组。
使用传递给 GetObjects 的 IWbemObjectAccess 方法访问枚举器的属性。
属性句柄可以传递给每个 IWbemObjectAccess 实例,以检索刷新的值。 客户端必须调用 Release 来释放 GetObjects 返回的 IWbemObjectAccess 指针。
示例
以下 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;
}
相关主题