Доступ к данным о производительности в C++
Высокопроизводительный API WMI — это серия интерфейсов, которые получают данные из классов счетчиков производительности. Эти интерфейсы требуют использования объекта средства обновления для увеличения частоты выборки. Дополнительные сведения об использовании объекта refresher в скриптах см. в разделах Доступ к данным о производительности в разделе Задачи скрипта и WMI: мониторинг производительности.
В этой статье рассматриваются следующие разделы:
- Обновление данных о производительности
- Добавление перечислителей в средство обновления WMI
- Пример
- Связанные темы
Обновление данных о производительности
Объект средства обновления повышает производительность поставщика данных и клиента, извлекая данные без пересечения границ процесса. Если клиент и сервер находятся на одном компьютере, средство обновления загружает высокопроизводительный поставщик в процессе на клиент и копирует данные непосредственно из объектов поставщика в клиентские объекты. Если клиент и сервер расположены на разных компьютерах, средство обновления повышает производительность за счет кэширования объектов на удаленном компьютере и передачи клиенту минимальных наборов данных.
Средство обновления также:
Автоматически повторно подключает клиент к удаленной службе WMI при возникновении сетевой ошибки или перезапуске удаленного компьютера.
По умолчанию средство обновления пытается повторно подключить приложение к соответствующему высокопроизводительный поставщику при сбое удаленного подключения между двумя компьютерами. Чтобы предотвратить повторное подключение, передайте флаг WBEM_FLAG_REFRESH_NO_AUTO_RECONNECT в вызове метода Refresh . Клиенты сценариев должны задать для свойства SWbemRefresher.AutoReconnectзначение FALSE.
Загружает несколько объектов и перечислителей, предоставляемых одинаковыми или разными поставщиками.
Позволяет добавлять в средство обновления несколько объектов, перечислителей или и то, и другое.
Перечисляет объекты .
Как и другие поставщики, высокопроизводительный поставщик может перечислять объекты.
После завершения написания высокопроизводительного клиента может потребоваться увеличить время отклика. Так как интерфейс IWbemObjectAccess оптимизирован для скорости, интерфейс не является встроенным threadsafe. Поэтому во время операции обновления не обращаться к обновляемому объекту или перечислению. Чтобы защитить объекты в потоках во время вызовов методов 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")
В следующей процедуре показано, как добавить перечислитель в средство обновления.
Добавление перечислителя в средство обновления
Вызовите метод 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;
Создайте цикл, который выполняет следующие действия:
Обновляет объект с помощью вызова 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;
}
Связанные темы