Zugreifen auf Leistungsdaten in C++
Die WMI-Hochleistungs-API besteht aus einer Reihe von Schnittstellen, die Daten aus Leistungsindikatorklassen abrufen. Diese Schnittstellen erfordern die Verwendung eines Aktualisierungsobjekts, um die Samplingrate zu erhöhen. Weitere Informationen zur Verwendung des Aktualisierungsobjekts in Skripts finden Sie unter Zugreifen auf Leistungsdaten in Skript und WMI-Aufgaben: Leistungsüberwachung.
In diesem Themenbereich werden die folgenden Abschnitte behandelt:
- Aktualisieren von Leistungsdaten
- Hinzufügen von Enumeratoren zur WMI-Aktualisierung
- Beispiel
- Zugehörige Themen
Aktualisieren von Leistungsdaten
Ein Aktualisierungsobjekt erhöht die Leistung des Datenanbieters und des Clients, indem Daten abgerufen werden, ohne Prozessgrenzen zu überschreiten. Wenn sich sowohl der Client als auch der Server auf demselben Computer befinden, lädt eine Aktualisierung den Hochleistungsanbieter im Prozess auf den Client und kopiert Daten direkt aus Anbieterobjekten in Clientobjekte. Wenn sich der Client und der Server auf unterschiedlichen Computern befinden, erhöht die Aktualisierung die Leistung, indem Objekte auf dem Remotecomputer zwischengespeichert und minimale Datasets an den Client übertragen werden.
Ein Aktualisierungsobjekt führt außerdem Folgendes durch:
Verbindet einen Client automatisch wieder mit einem WMI-Remotedienst, wenn ein Netzwerkfehler auftritt oder der Remotecomputer neu gestartet wird.
Standardmäßig versucht eine Aktualisierung, Ihre Anwendung erneut mit dem relevanten Hochleistungsanbieter zu verbinden, wenn eine Remoteverbindung zwischen den beiden Computern fehlschlägt. Um die erneute Verbindung zu verhindern, übergeben Sie das Flag WBEM_FLAG_REFRESH_NO_AUTO_RECONNECT im Methodenaufruf Refresh . Skriptclients müssen die Eigenschaft SWbemRefresher.AutoReconnect auf FALSE festlegen.
Lädt mehrere Objekte und Enumeratoren, die von demselben oder verschiedenen Anbietern bereitgestellt werden.
Ermöglicht das Hinzufügen mehrerer Objekte, Enumeratoren oder beides zu einer Aktualisierung.
Listet Objekte auf.
Wie andere Anbieter kann ein Hochleistungsanbieter Objekte auflisten.
Nachdem Sie mit dem Schreiben Ihres Hochleistungsclients fertig sind, möchten Sie möglicherweise Ihre Antwortzeit verbessern. Da die Schnittstelle IWbemObjectAccess für die Geschwindigkeit optimiert ist, ist die Schnittstelle nicht intrinsisch threadsicher. Greifen Sie daher während eines Aktualisierungsvorgangs nicht auf das aktualisierbare Objekt oder die Enumeration zu. Verwenden Sie zum Threadübergreifenden Schutz von Objekten während Methodenaufrufen IWbemObjectAccess die Methoden IWbemObjectAccess::Lock und Unlock . Um die Leistung zu verbessern, synchronisieren Sie Ihre Threads, sodass Sie einzelne Threads nicht sperren müssen. Das Reduzieren von Threads und das Synchronisieren von Objektgruppen für Aktualisierungsvorgänge bietet die beste Gesamtleistung.
Hinzufügen von Enumeratoren zur WMI-Aktualisierung
Sowohl die Anzahl der Instanzen als auch die Daten in den einzelnen Instanz werden aktualisiert, indem der Aktualisierung ein Enumerator hinzugefügt wird, sodass jeder Aufruf von IWbemRefresher::Refresh zu einer vollständigen Enumeration führt.
Das folgende C++-Codebeispiel erfordert die folgenden Verweise und #include-Anweisungen für eine ordnungsgemäße Kompilierung.
#define _WIN32_DCOM
#include <iostream>
using namespace std;
#include <Wbemidl.h>
#pragma comment(lib, "wbemuuid.lib")
Das folgende Verfahren zeigt, wie Sie einer Aktualisierung einen Enumerator hinzufügen.
So fügen Sie einem Aktualisierungsobjekt einen Enumerator hinzu
Rufen Sie die Methode IWbemConfigureRefresher::AddEnum auf, indem Sie den Pfad zum aktualisierbaren Objekt und die Schnittstelle IWbemServices verwenden.
Die Aktualisierung gibt einen Zeiger auf eine Schnittstelle IWbemHiPerfEnum zurück. Sie können die Schnittstelle IWbemHiPerfEnum verwenden, um auf die Objekte in der Enumeration zuzugreifen.
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;
Erstellen Sie eine Schleife, die die folgenden Aktionen ausführt:
Aktualisiert das Objekt mithilfe eines Aufrufs von IWbemRefresher::Refresh.
Stellt ein Array von Schnittstellenzeigern IWbemObjectAccess auf die Methode IWbemHiPerfEnum::GetObjects bereit.
Greift mithilfe der Methoden IWbemObjectAccess , die an GetObjects übergeben werden, auf die Eigenschaften des Enumerators zu.
Ein Eigenschaftenhandle kann an jede Instanz IWbemObjectAccess übergeben werden, um den aktualisierten Wert abzurufen. Der Client muss Release aufrufen, um die Zeiger IWbemObjectAccess freizugeben, die von GetObjects zurückgegeben werden.
Beispiel
Im folgenden C++-Codebeispiel wird eine Hochleistungsklasse aufgelistet, bei der der Client ein Eigenschaftenhandle aus dem ersten Objekt abruft und das Handle für den Rest des Aktualisierungsvorgangs wiederverwendet. Bei jedem Aufruf der Methode Refresh werden die Anzahl der Instanzen und die Instanzdaten aktualisiert.
#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;
}
Zugehörige Themen