Accès aux données de performances en C++
L’API hautes performances WMI est une série d’interfaces qui obtiennent des données à partir de classes de compteur de performances. Ces interfaces nécessitent l’utilisation d’un objet actualisateur pour augmenter le taux d’échantillonnage. Pour plus d’informations sur l’utilisation de l’objet actualisateur dans les scripts, consultez Accès aux données de performances dans le script et Tâches WMI : Analyse des performances.
Les sections suivantes sont abordées dans cette rubrique :
- Actualisation des données de performances
- Ajout d’énumérateurs à l’actualisateur WMI
- Exemple
- Rubriques connexes
Actualisation des données de performances
Un objet actualisateur augmente les performances du fournisseur de données et du client en récupérant des données sans dépasser les limites du processus. Si le client et le serveur se trouvent sur le même ordinateur, un actualisateur charge le fournisseur hautes performances in-process sur le client et copie les données directement des objets fournisseurs dans des objets client. Si le client et le serveur se trouvent sur des ordinateurs différents, l’actualisateur augmente les performances en mettant en cache les objets sur l’ordinateur distant et en transmettant des jeux de données minimaux au client.
Un actualisateur effectue également les opérations suivantes :
Il reconnecte automatiquement un client à un service WMI distant quand une erreur réseau se produit ou que l’ordinateur distant est redémarré.
Par défaut, un actualisateur tente de reconnecter votre application au fournisseur hautes performances approprié en cas d’échec d’une connexion à distance entre les deux ordinateurs. Pour empêcher la reconnexion, transmettez l’indicateur WBEM_FLAG_REFRESH_NO_AUTO_RECONNECT dans l’appel de la méthode Refresh. Les clients de script doivent définir la propriété SWbemRefresher.AutoReconnect sur FALSE.
Il charge plusieurs objets et énumérateurs fournis par le même fournisseur ou par des fournisseurs différents.
Cela vous permet d’ajouter plusieurs objets, énumérateurs ou les deux à un actualisateur.
Il énumère les objets.
Comme d’autres fournisseurs, un fournisseur hautes performances peut énumérer des objets.
Une fois que vous aurez terminé d’écrire votre client hautes performances, vous souhaiterez peut-être améliorer votre temps de réponse. Comme l’interface IWbemObjectAccess est optimisée pour la vitesse, l’interface n’est pas intrinsèquement sécurisée au niveau des threads. Par conséquent, pendant une opération d’actualisation, n’accédez pas à l’objet ou à l’énumération actualisable. Pour protéger les objets sur les threads pendant les appels de méthode IWbemObjectAccess, utilisez les méthodes IWbemObjectAccess::Lock et Unlock. Pour améliorer les performances, synchronisez vos threads pour ne pas avoir besoin de verrouiller des threads individuels. La réduction des threads et la synchronisation des groupes d’objets pour les opérations d’actualisation offrent les meilleures performances globales.
Ajout d’énumérateurs à l’actualisateur WMI
Le nombre d’instances et de données dans chaque instance sont actualisés en ajoutant un énumérateur à l’actualisateur afin que chaque appel à IWbemRefresher::Refresh entraîne une énumération complète.
L’exemple de code C++ suivant nécessite les références et les instructions #include suivantes pour être compilé correctement.
#define _WIN32_DCOM
#include <iostream>
using namespace std;
#include <Wbemidl.h>
#pragma comment(lib, "wbemuuid.lib")
La procédure suivante montre comment ajouter un énumérateur à un actualisateur.
Pour ajouter un énumérateur à un actualisateur
Appelez la méthode IWbemConfigureRefresher::AddEnum à l’aide du chemin d’accès à l’objet actualisable et de l’interface IWbemServices.
L’actualisateur retourne un pointeur vers une interface IWbemHiPerfEnum. Vous pouvez utiliser l’interface IWbemHiPerfEnum pour accéder aux objets de l’énumération.
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;
Créez une boucle qui effectue les actions suivantes :
Actualise l’objet à l’aide d’un appel à IWbemRefresher::Refresh.
Fournit un tableau de pointeurs d’interface IWbemObjectAccess à la méthode IWbemHiPerfEnum::GetObjects.
Accède aux propriétés de l’énumérateur à l’aide des méthodes IWbemObjectAccess transmises à GetObjects.
Un handle de propriété peut être transmis à chaque instance IWbemObjectAccess pour récupérer la valeur actualisée. Le client doit appeler Release pour libérer les pointeurs IWbemObjectAccess retournés par GetObjects.
Exemple
L’exemple de code C++ suivant énumère une classe hautes performances, où le client récupère un handle de propriété à partir du premier objet et réutilise le handle pour le reste de l’opération d’actualisation. Chaque appel à la méthode Refresh met à jour le nombre d’instances et les données d’instance.
#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;
}
Rubriques connexes