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
- Adición de enumeradores al actualizador de WMI
- Ejemplo
- Temas relacionados
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
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;
Cree un bucle que realice las siguientes acciones:
Actualizar el objeto mediante una llamada a IWbemRefresher::Refresh.
Proporcionar una matriz de punteros de interfaz IWbemObjectAccess al método IWbemHiPerfEnum::GetObjects.
Acceder a las propiedades del enumerador mediante los métodos IWbemObjectAccess pasados a GetObjects.
Se puede pasar un identificador de propiedad a cada instancia de IWbemObjectAccess para recuperar el valor actualizado. El cliente debe llamar a Release para liberar los punteros IWbemObjectAccess devueltos por GetObjects.
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;
}
Temas relacionados