[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [RFC 3/3] qga: implement get-memory-info on win32
From: |
marcandre . lureau |
Subject: |
[Qemu-devel] [RFC 3/3] qga: implement get-memory-info on win32 |
Date: |
Fri, 31 Jul 2015 19:36:49 +0200 |
From: Marc-André Lureau <address@hidden>
Signed-off-by: Marc-André Lureau <address@hidden>
---
configure | 1 +
qga/commands-win32.c | 164 ++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 163 insertions(+), 2 deletions(-)
diff --git a/configure b/configure
index c5c4b82..82ee185 100755
--- a/configure
+++ b/configure
@@ -734,6 +734,7 @@ if test "$mingw32" = "yes" ; then
local_statedir=
confsuffix=""
libs_qga="-lws2_32 -lwinmm -lpowrprof -liphlpapi -lnetapi32 $libs_qga"
+ libs_qga="-lole32 -loleaut32 -lwbemuuid -lpsapi $libs_qga"
fi
werror=""
diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index bf9cd93..be11221 100644
--- a/qga/commands-win32.c
+++ b/qga/commands-win32.c
@@ -27,6 +27,8 @@
#include <initguid.h>
#endif
#include <lm.h>
+#include <wbemcli.h>
+#include <psapi.h>
#include "qga/guest-agent-core.h"
#include "qga/vss-win32.h"
@@ -1333,8 +1335,166 @@ void ga_command_state_init(GAState *s, GACommandState
*cs)
ga_command_state_add(cs, guest_file_init, NULL);
}
+#define chk(msg) \
+ do { \
+ if (FAILED(hr)) { \
+ gchar *emsg = g_win32_error_message(GetLastError()); \
+ slog("Failed to %s: %s", (msg), emsg); \
+ g_free(emsg); \
+ goto out; \
+ } \
+ } while (0)
+
+static gboolean get_memory_wmi_info(GuestMemoryInfo *info)
+{
+ HRESULT hr = 0;
+ IWbemLocator *locator = NULL;
+ IWbemServices *services = NULL;
+ IEnumWbemClassObject *results = NULL;
+ BSTR resource, language, query_perf, query_swap;
+ gboolean success = FALSE;
+
+ g_return_val_if_fail(info != NULL, FALSE);
+
+ resource = SysAllocString(L"ROOT\\CIMV2");
+ language = SysAllocString(L"WQL");
+ query_perf = SysAllocString(L"SELECT * FROM "
+ "Win32_PerfFormattedData_PerfOS_Memory");
+ query_swap = SysAllocString(L"SELECT * FROM "
+ "Win32_PageFileUsage");
+
+ /* initialize COM */
+ hr = CoInitializeEx(0, COINIT_MULTITHREADED);
+ chk("initialize COM");
+
+ hr = CoInitializeSecurity(NULL, -1, NULL, NULL,
+ RPC_C_AUTHN_LEVEL_DEFAULT,
+ RPC_C_IMP_LEVEL_IMPERSONATE,
+ NULL, EOAC_NONE, NULL);
+ chk("initialize COM security");
+
+ /* connect to WMI */
+ hr = CoCreateInstance(&CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER,
+ &IID_IWbemLocator, (LPVOID *) &locator);
+ chk("create WbemLocator instance");
+
+ hr = locator->lpVtbl->ConnectServer(locator, resource, NULL, NULL, NULL, 0,
+ NULL, NULL, &services);
+ chk("connect to CIMV2 server");
+
+ /* issue a WMI perf query */
+ hr = services->lpVtbl->ExecQuery(services, language, query_perf,
+ WBEM_FLAG_BIDIRECTIONAL, NULL, &results);
+ chk("execute perf query");
+
+ if (results != NULL) {
+ IWbemClassObject *result = NULL;
+ ULONG returnedCount = 0;
+
+ /* enumerate the retrieved objects */
+ while ((hr = results->lpVtbl->Next(results, WBEM_INFINITE, 1,
+ &result, &returnedCount)) == S_OK) {
+ VARIANT pages_in, pages_out, pf, pfr;
+
+ hr = result->lpVtbl->Get(result, L"PagesInputPersec", 0,
+ &pages_in, 0, 0);
+ hr = result->lpVtbl->Get(result, L"PagesOutputPersec", 0,
+ &pages_out, 0, 0);
+ hr = result->lpVtbl->Get(result, L"PageFaultsPersec", 0,
+ &pf, 0, 0);
+ hr = result->lpVtbl->Get(result, L"PageReadsPersec", 0,
+ &pfr, 0, 0);
+
+ info->swap_in += pages_in.ulVal;
+ info->swap_out += pages_out.ulVal;
+ info->pf_minor += pf.ulVal - pfr.ulVal;
+ info->pf_major += pfr.ulVal;
+
+ result->lpVtbl->Release(result);
+ }
+
+ results->lpVtbl->Release(results);
+ }
+
+ /* issue a WMI swap query */
+ hr = services->lpVtbl->ExecQuery(services, language, query_swap,
+ WBEM_FLAG_BIDIRECTIONAL, NULL, &results);
+ chk("execute swap query");
+
+ if (results != NULL) {
+ IWbemClassObject *result = NULL;
+ ULONG returnedCount = 0;
+
+ /* enumerate the retrieved objects */
+ while ((hr = results->lpVtbl->Next(results, WBEM_INFINITE, 1,
+ &result, &returnedCount)) == S_OK) {
+ VARIANT usage, alloc;
+
+ hr = result->lpVtbl->Get(result, L"AllocatedBaseSize", 0,
+ &alloc, 0, 0);
+ hr = result->lpVtbl->Get(result, L"CurrentUsage", 0,
+ &usage, 0, 0);
+
+ /* MiB to kiB */
+ info->swap_total += alloc.ulVal * 1024;
+ info->swap_free += (alloc.ulVal - usage.ulVal) * 1024;
+
+ result->lpVtbl->Release(result);
+ }
+
+ results->lpVtbl->Release(results);
+ }
+
+ success = TRUE;
+
+out:
+ /* release WMI COM interfaces */
+ if (services) {
+ services->lpVtbl->Release(services);
+ }
+ if (locator) {
+ locator->lpVtbl->Release(locator);
+ }
+
+ /* unwind everything else we've allocated */
+ CoUninitialize();
+
+ if (query_perf) {
+ SysFreeString(query_perf);
+ }
+ if (query_swap) {
+ SysFreeString(query_swap);
+ }
+ if (language) {
+ SysFreeString(language);
+ }
+ if (resource) {
+ SysFreeString(resource);
+ }
+
+ return success;
+}
+
GuestMemoryInfo *qmp_guest_get_memory_info(Error **errp)
{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
+ GuestMemoryInfo *info = g_new0(GuestMemoryInfo, 1);
+ PERFORMANCE_INFORMATION perf = { .cb = sizeof(PERFORMANCE_INFORMATION) };
+
+ if (!get_memory_wmi_info(info)) {
+ error_setg(errp, "Failed to get WMI info");
+ g_free(info);
+ return NULL;
+ }
+
+ if (!GetPerformanceInfo(&perf, perf.cb)) {
+ error_setg(errp, "Failed to get performance info");
+ g_free(info);
+ return NULL;
+ }
+
+ info->mem_total = (perf.PhysicalTotal * perf.PageSize) / 1024;
+ info->mem_free = (perf.PhysicalAvailable * perf.PageSize) / 1024;
+ info->mem_cached = (perf.SystemCache * perf.PageSize) / 1024;
+
+ return info;
}
--
2.4.3