Report CPU load average for Windows VMs
Resolves: RHEL-71884 - Report CPU load average for Windows VMs Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
This commit is contained in:
parent
aad12f6898
commit
d3ae0027cb
131
20241202_berrange_qga_implement_a_guest_get_load_command.mbx
Normal file
131
20241202_berrange_qga_implement_a_guest_get_load_command.mbx
Normal file
@ -0,0 +1,131 @@
|
||||
From git@z Thu Jan 1 00:00:00 1970
|
||||
Subject: [PATCH] qga: implement a 'guest-get-load' command
|
||||
From: "Daniel P. Berrangé" <berrange@redhat.com>
|
||||
Date: Mon, 02 Dec 2024 12:19:27 +0000
|
||||
Message-Id: <20241202121927.864335-1-berrange@redhat.com>
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Provide a way to report the process load average, via a new
|
||||
'guest-get-load' command.
|
||||
|
||||
This is only implemented for POSIX platforms providing 'getloadavg'.
|
||||
|
||||
Example illustrated with qmp-shell:
|
||||
|
||||
(QEMU) guest-get-load
|
||||
{
|
||||
"return": {
|
||||
"load15m": 1.546875,
|
||||
"load1m": 1.669921875,
|
||||
"load5m": 1.9306640625
|
||||
}
|
||||
}
|
||||
|
||||
Windows has no native equivalent API, but it would be possible to
|
||||
simulate it as illustrated here (BSD-3-Clause):
|
||||
|
||||
https://github.com/giampaolo/psutil/pull/1485
|
||||
|
||||
This is left as an exercise for future contributors.
|
||||
|
||||
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
|
||||
Reviewed-by: Konstantin Kostiuk <kkostiuk@redhat.com>
|
||||
---
|
||||
meson.build | 1 +
|
||||
qga/commands-posix.c | 20 ++++++++++++++++++++
|
||||
qga/qapi-schema.json | 37 +++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 58 insertions(+)
|
||||
|
||||
diff --git a/meson.build b/meson.build
|
||||
index a290dbfa33..9c65e56fff 100644
|
||||
--- a/meson.build
|
||||
+++ b/meson.build
|
||||
@@ -2619,6 +2619,7 @@ config_host_data.set('CONFIG_SETNS', cc.has_function('setns') and cc.has_functio
|
||||
config_host_data.set('CONFIG_SYNCFS', cc.has_function('syncfs'))
|
||||
config_host_data.set('CONFIG_SYNC_FILE_RANGE', cc.has_function('sync_file_range'))
|
||||
config_host_data.set('CONFIG_TIMERFD', cc.has_function('timerfd_create'))
|
||||
+config_host_data.set('CONFIG_GETLOADAVG', cc.has_function('getloadavg'))
|
||||
config_host_data.set('HAVE_COPY_FILE_RANGE', cc.has_function('copy_file_range'))
|
||||
config_host_data.set('HAVE_GETIFADDRS', cc.has_function('getifaddrs'))
|
||||
config_host_data.set('HAVE_GLIB_WITH_SLICE_ALLOCATOR', glib_has_gslice)
|
||||
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
|
||||
index 636307bedf..6e3c15f539 100644
|
||||
--- a/qga/commands-posix.c
|
||||
+++ b/qga/commands-posix.c
|
||||
@@ -1368,3 +1368,23 @@ char *qga_get_host_name(Error **errp)
|
||||
|
||||
return g_steal_pointer(&hostname);
|
||||
}
|
||||
+
|
||||
+#ifdef CONFIG_GETLOADAVG
|
||||
+GuestLoadAverage *qmp_guest_get_load(Error **errp)
|
||||
+{
|
||||
+ double loadavg[3];
|
||||
+ GuestLoadAverage *ret = NULL;
|
||||
+
|
||||
+ if (getloadavg(loadavg, G_N_ELEMENTS(loadavg)) < 0) {
|
||||
+ error_setg_errno(errp, errno,
|
||||
+ "cannot query load average");
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ ret = g_new0(GuestLoadAverage, 1);
|
||||
+ ret->load1m = loadavg[0];
|
||||
+ ret->load5m = loadavg[1];
|
||||
+ ret->load15m = loadavg[2];
|
||||
+ return ret;
|
||||
+}
|
||||
+#endif
|
||||
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
|
||||
index 0537bb7886..995594aaf4 100644
|
||||
--- a/qga/qapi-schema.json
|
||||
+++ b/qga/qapi-schema.json
|
||||
@@ -1843,6 +1843,43 @@
|
||||
'if': 'CONFIG_LINUX'
|
||||
}
|
||||
|
||||
+
|
||||
+##
|
||||
+# @GuestLoadAverage:
|
||||
+#
|
||||
+# Statistics about process load information
|
||||
+#
|
||||
+# @load1m: 1-minute load avage
|
||||
+#
|
||||
+# @load5m: 5-minute load avage
|
||||
+#
|
||||
+# @load15m: 15-minute load avage
|
||||
+#
|
||||
+# Since: 10.0
|
||||
+##
|
||||
+{ 'struct': 'GuestLoadAverage',
|
||||
+ 'data': {
|
||||
+ 'load1m': 'number',
|
||||
+ 'load5m': 'number',
|
||||
+ 'load15m': 'number'
|
||||
+ },
|
||||
+ 'if': 'CONFIG_GETLOADAVG'
|
||||
+}
|
||||
+
|
||||
+##
|
||||
+# @guest-get-load:
|
||||
+#
|
||||
+# Retrieve CPU process load information
|
||||
+#
|
||||
+# Returns: load information
|
||||
+#
|
||||
+# Since: 10.0
|
||||
+##
|
||||
+{ 'command': 'guest-get-load',
|
||||
+ 'returns': 'GuestLoadAverage',
|
||||
+ 'if': 'CONFIG_GETLOADAVG'
|
||||
+}
|
||||
+
|
||||
##
|
||||
# @GuestNetworkRoute:
|
||||
#
|
||||
--
|
||||
2.46.0
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
Name: mingw-qemu-ga-win
|
||||
Version: 109.1.0
|
||||
Release: 7%{?dist}
|
||||
Release: 8%{?dist}
|
||||
Summary: Qemus Guest agent for Windows
|
||||
|
||||
Group: System Environment/Daemons
|
||||
@ -20,6 +20,8 @@ Source0: https://gitlab.com/qemu-project/qemu/-/archive/v%{qemu_version}/qemu-v%
|
||||
|
||||
Patch0001: 0001-Change-Version.patch
|
||||
Patch0002: 20241210_demeng_qemu_ga_win_fix_a_typo_error.mbx
|
||||
Patch0003: 20241202_berrange_qga_implement_a_guest_get_load_command.mbx
|
||||
Patch0004: v2_20250324_kkostiuk_qga_add_guest_get_load_command.mbx
|
||||
|
||||
BuildArch: noarch
|
||||
# RHEL-57753 - mingw-qemu-ga-win failed to build on s390x
|
||||
@ -70,6 +72,8 @@ This package does not need to be installed on the host OS.
|
||||
%setup -q -n qemu-v%{qemu_version}
|
||||
%patch0001 -p1
|
||||
%patch0002 -p1
|
||||
%patch0003 -p1
|
||||
%patch0004 -p1
|
||||
|
||||
%build
|
||||
|
||||
@ -126,6 +130,9 @@ cp build/qga/qemu-ga-x86_64.msi $RPM_BUILD_ROOT%{mingw64_bindir}
|
||||
%{mingw64_bindir}/qemu-ga*
|
||||
|
||||
%changelog
|
||||
* Mon Mar 17 2025 Konstantin Kostiuk <kkostiuk@redhat.com> 109.1.0-8
|
||||
- RHEL-71884 - [qemu-guest-agent][RFE] Report CPU load average for Windows VMs
|
||||
|
||||
* Mon Jan 20 2025 Konstantin Kostiuk <kkostiuk@redhat.com> 109.1.0-7
|
||||
- RHEL-74469 - Rebuild mingw-qemu-ga-win package due to deps update
|
||||
|
||||
|
405
v2_20250324_kkostiuk_qga_add_guest_get_load_command.mbx
Normal file
405
v2_20250324_kkostiuk_qga_add_guest_get_load_command.mbx
Normal file
@ -0,0 +1,405 @@
|
||||
From git@z Thu Jan 1 00:00:00 1970
|
||||
Subject: [PATCH v2 1/2] qga-win: implement a 'guest-get-load' command
|
||||
From: Konstantin Kostiuk <kkostiuk@redhat.com>
|
||||
Date: Mon, 24 Mar 2025 15:17:28 +0200
|
||||
Message-Id: <20250324131729.70992-2-kkostiuk@redhat.com>
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Windows has no native equivalent API, but it would be possible to
|
||||
simulate it as illustrated here (BSD-3-Clause):
|
||||
|
||||
https://github.com/giampaolo/psutil/pull/1485
|
||||
|
||||
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
|
||||
Tested-by: Dehan Meng <demeng@redhat.com>
|
||||
Reviewed-by: Yan Vugenfirer <yvugenfi@redhat.com>
|
||||
Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
|
||||
---
|
||||
qga/commands-win32.c | 148 +++++++++++++++++++++++++++++++++++++++++
|
||||
qga/guest-agent-core.h | 10 +++
|
||||
qga/main.c | 39 +++++++++++
|
||||
qga/meson.build | 2 +-
|
||||
qga/qapi-schema.json | 9 ++-
|
||||
5 files changed, 205 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/qga/commands-win32.c b/qga/commands-win32.c
|
||||
index 749fdf8895..ba72bface7 100644
|
||||
--- a/qga/commands-win32.c
|
||||
+++ b/qga/commands-win32.c
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <lm.h>
|
||||
#include <wtsapi32.h>
|
||||
#include <wininet.h>
|
||||
+#include <pdh.h>
|
||||
|
||||
#include "guest-agent-core.h"
|
||||
#include "vss-win32.h"
|
||||
@@ -119,6 +120,28 @@ static OpenFlags guest_file_open_modes[] = {
|
||||
{"a+b", FILE_GENERIC_APPEND | GENERIC_READ, OPEN_ALWAYS }
|
||||
};
|
||||
|
||||
+/*
|
||||
+ * We use an exponentially weighted moving average, just like Unix systems do
|
||||
+ * https://en.wikipedia.org/wiki/Load_(computing)#Unix-style_load_calculation
|
||||
+ *
|
||||
+ * These constants serve as the damping factor and are calculated with
|
||||
+ * 1 / exp(sampling interval in seconds / window size in seconds)
|
||||
+ *
|
||||
+ * This formula comes from linux's include/linux/sched/loadavg.h
|
||||
+ * https://github.com/torvalds/linux/blob/345671ea0f9258f410eb057b9ced9cefbbe5dc78/include/linux/sched/loadavg.h#L20-L23
|
||||
+ */
|
||||
+#define LOADAVG_FACTOR_1F 0.9200444146293232478931553241
|
||||
+#define LOADAVG_FACTOR_5F 0.9834714538216174894737477501
|
||||
+#define LOADAVG_FACTOR_15F 0.9944598480048967508795473394
|
||||
+/*
|
||||
+ * The time interval in seconds between taking load counts, same as Linux
|
||||
+ */
|
||||
+#define LOADAVG_SAMPLING_INTERVAL 5
|
||||
+
|
||||
+double load_avg_1m;
|
||||
+double load_avg_5m;
|
||||
+double load_avg_15m;
|
||||
+
|
||||
#define debug_error(msg) do { \
|
||||
char *suffix = g_win32_error_message(GetLastError()); \
|
||||
g_debug("%s: %s", (msg), suffix); \
|
||||
@@ -2448,3 +2471,128 @@ char *qga_get_host_name(Error **errp)
|
||||
|
||||
return g_utf16_to_utf8(tmp, size, NULL, NULL, NULL);
|
||||
}
|
||||
+
|
||||
+
|
||||
+static VOID CALLBACK load_avg_callback(PVOID hCounter, BOOLEAN timedOut)
|
||||
+{
|
||||
+ PDH_FMT_COUNTERVALUE displayValue;
|
||||
+ double currentLoad;
|
||||
+ PDH_STATUS err;
|
||||
+
|
||||
+ err = PdhGetFormattedCounterValue(
|
||||
+ (PDH_HCOUNTER)hCounter, PDH_FMT_DOUBLE, 0, &displayValue);
|
||||
+ /* Skip updating the load if we can't get the value successfully */
|
||||
+ if (err != ERROR_SUCCESS) {
|
||||
+ slog("PdhGetFormattedCounterValue failed to get load value with 0x%lx",
|
||||
+ err);
|
||||
+ return;
|
||||
+ }
|
||||
+ currentLoad = displayValue.doubleValue;
|
||||
+
|
||||
+ load_avg_1m = load_avg_1m * LOADAVG_FACTOR_1F + currentLoad * \
|
||||
+ (1.0 - LOADAVG_FACTOR_1F);
|
||||
+ load_avg_5m = load_avg_5m * LOADAVG_FACTOR_5F + currentLoad * \
|
||||
+ (1.0 - LOADAVG_FACTOR_5F);
|
||||
+ load_avg_15m = load_avg_15m * LOADAVG_FACTOR_15F + currentLoad * \
|
||||
+ (1.0 - LOADAVG_FACTOR_15F);
|
||||
+}
|
||||
+
|
||||
+static BOOL init_load_avg_counter(Error **errp)
|
||||
+{
|
||||
+ CONST WCHAR *szCounterPath = L"\\System\\Processor Queue Length";
|
||||
+ PDH_STATUS status;
|
||||
+ BOOL ret;
|
||||
+ HQUERY hQuery;
|
||||
+ HCOUNTER hCounter;
|
||||
+ HANDLE event;
|
||||
+ HANDLE waitHandle;
|
||||
+
|
||||
+ status = PdhOpenQueryW(NULL, 0, &hQuery);
|
||||
+ if (status != ERROR_SUCCESS) {
|
||||
+ /*
|
||||
+ * If the function fails, the return value is a system error code or
|
||||
+ * a PDH error code. error_setg_win32 cant translate PDH error code
|
||||
+ * properly, so just report it as is.
|
||||
+ */
|
||||
+ error_setg_win32(errp, (DWORD)status,
|
||||
+ "PdhOpenQueryW failed with 0x%lx", status);
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ status = PdhAddEnglishCounterW(hQuery, szCounterPath, 0, &hCounter);
|
||||
+ if (status != ERROR_SUCCESS) {
|
||||
+ error_setg_win32(errp, (DWORD)status,
|
||||
+ "PdhAddEnglishCounterW failed with 0x%lx. Performance counters may be disabled.",
|
||||
+ status);
|
||||
+ PdhCloseQuery(hQuery);
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ event = CreateEventW(NULL, FALSE, FALSE, L"LoadUpdateEvent");
|
||||
+ if (event == NULL) {
|
||||
+ error_setg_win32(errp, GetLastError(), "Create LoadUpdateEvent failed");
|
||||
+ PdhCloseQuery(hQuery);
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ status = PdhCollectQueryDataEx(hQuery, LOADAVG_SAMPLING_INTERVAL, event);
|
||||
+ if (status != ERROR_SUCCESS) {
|
||||
+ error_setg_win32(errp, (DWORD)status,
|
||||
+ "PdhCollectQueryDataEx failed with 0x%lx", status);
|
||||
+ CloseHandle(event);
|
||||
+ PdhCloseQuery(hQuery);
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ ret = RegisterWaitForSingleObject(
|
||||
+ &waitHandle,
|
||||
+ event,
|
||||
+ (WAITORTIMERCALLBACK)load_avg_callback,
|
||||
+ (PVOID)hCounter,
|
||||
+ INFINITE,
|
||||
+ WT_EXECUTEDEFAULT);
|
||||
+
|
||||
+ if (ret == 0) {
|
||||
+ error_setg_win32(errp, GetLastError(),
|
||||
+ "RegisterWaitForSingleObject failed");
|
||||
+ CloseHandle(event);
|
||||
+ PdhCloseQuery(hQuery);
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ ga_set_load_avg_wait_handle(ga_state, waitHandle);
|
||||
+ ga_set_load_avg_event(ga_state, event);
|
||||
+ ga_set_load_avg_pdh_query(ga_state, hQuery);
|
||||
+
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
+GuestLoadAverage *qmp_guest_get_load(Error **errp)
|
||||
+{
|
||||
+ /*
|
||||
+ * The load average logic calls PerformaceCounterAPI, which can result
|
||||
+ * in a performance penalty. This avoids running the load average logic
|
||||
+ * until a management application actually requests it. The load average
|
||||
+ * will not initially be very accurate, but assuming that any interested
|
||||
+ * management application will request it repeatedly throughout the lifetime
|
||||
+ * of the VM, this seems like a good mitigation.
|
||||
+ */
|
||||
+ if (ga_get_load_avg_pdh_query(ga_state) == NULL) {
|
||||
+ /* set initial values */
|
||||
+ load_avg_1m = 0;
|
||||
+ load_avg_5m = 0;
|
||||
+ load_avg_15m = 0;
|
||||
+
|
||||
+ if (init_load_avg_counter(errp) == false) {
|
||||
+ return NULL;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ GuestLoadAverage *ret = NULL;
|
||||
+
|
||||
+ ret = g_new0(GuestLoadAverage, 1);
|
||||
+ ret->load1m = load_avg_1m;
|
||||
+ ret->load5m = load_avg_5m;
|
||||
+ ret->load15m = load_avg_15m;
|
||||
+ return ret;
|
||||
+}
|
||||
diff --git a/qga/guest-agent-core.h b/qga/guest-agent-core.h
|
||||
index a536d07d0d..d9f3922adf 100644
|
||||
--- a/qga/guest-agent-core.h
|
||||
+++ b/qga/guest-agent-core.h
|
||||
@@ -13,6 +13,10 @@
|
||||
#ifndef GUEST_AGENT_CORE_H
|
||||
#define GUEST_AGENT_CORE_H
|
||||
|
||||
+#ifdef _WIN32
|
||||
+#include <pdh.h>
|
||||
+#endif
|
||||
+
|
||||
#include "qapi/qmp/dispatch.h"
|
||||
#include "qga-qapi-types.h"
|
||||
|
||||
@@ -41,6 +45,12 @@ void ga_set_response_delimited(GAState *s);
|
||||
bool ga_is_frozen(GAState *s);
|
||||
void ga_set_frozen(GAState *s);
|
||||
void ga_unset_frozen(GAState *s);
|
||||
+#ifdef _WIN32
|
||||
+void ga_set_load_avg_event(GAState *s, HANDLE event);
|
||||
+void ga_set_load_avg_wait_handle(GAState *s, HANDLE wait_handle);
|
||||
+void ga_set_load_avg_pdh_query(GAState *s, HQUERY query);
|
||||
+HQUERY ga_get_load_avg_pdh_query(GAState *s);
|
||||
+#endif
|
||||
const char *ga_fsfreeze_hook(GAState *s);
|
||||
int64_t ga_get_fd_handle(GAState *s, Error **errp);
|
||||
int ga_parse_whence(GuestFileWhence *whence, Error **errp);
|
||||
diff --git a/qga/main.c b/qga/main.c
|
||||
index 72c39b042f..6c02f3ec38 100644
|
||||
--- a/qga/main.c
|
||||
+++ b/qga/main.c
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "qemu-version.h"
|
||||
#ifdef _WIN32
|
||||
#include <dbt.h>
|
||||
+#include <pdh.h>
|
||||
#include "qga/service-win32.h"
|
||||
#include "qga/vss-win32.h"
|
||||
#endif
|
||||
@@ -105,6 +106,9 @@ struct GAState {
|
||||
GAService service;
|
||||
HANDLE wakeup_event;
|
||||
HANDLE event_log;
|
||||
+ HANDLE load_avg_wait_handle;
|
||||
+ HANDLE load_avg_event;
|
||||
+ HQUERY load_avg_pdh_query;
|
||||
#endif
|
||||
bool delimit_response;
|
||||
bool frozen;
|
||||
@@ -582,6 +586,25 @@ const char *ga_fsfreeze_hook(GAState *s)
|
||||
}
|
||||
#endif
|
||||
|
||||
+#ifdef _WIN32
|
||||
+void ga_set_load_avg_wait_handle(GAState *s, HANDLE wait_handle)
|
||||
+{
|
||||
+ s->load_avg_wait_handle = wait_handle;
|
||||
+}
|
||||
+void ga_set_load_avg_event(GAState *s, HANDLE event)
|
||||
+{
|
||||
+ s->load_avg_event = event;
|
||||
+}
|
||||
+void ga_set_load_avg_pdh_query(GAState *s, HQUERY query)
|
||||
+{
|
||||
+ s->load_avg_pdh_query = query;
|
||||
+}
|
||||
+HQUERY ga_get_load_avg_pdh_query(GAState *s)
|
||||
+{
|
||||
+ return s->load_avg_pdh_query;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
static void become_daemon(const char *pidfile)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
@@ -1402,6 +1425,10 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation)
|
||||
g_debug("Guest agent version %s started", QEMU_FULL_VERSION);
|
||||
|
||||
#ifdef _WIN32
|
||||
+ s->load_avg_wait_handle = INVALID_HANDLE_VALUE;
|
||||
+ s->load_avg_event = INVALID_HANDLE_VALUE;
|
||||
+ s->load_avg_pdh_query = NULL;
|
||||
+
|
||||
s->event_log = RegisterEventSource(NULL, "qemu-ga");
|
||||
if (!s->event_log) {
|
||||
g_autofree gchar *errmsg = g_win32_error_message(GetLastError());
|
||||
@@ -1506,6 +1533,18 @@ static void cleanup_agent(GAState *s)
|
||||
#ifdef _WIN32
|
||||
CloseHandle(s->wakeup_event);
|
||||
CloseHandle(s->event_log);
|
||||
+
|
||||
+ if (s->load_avg_wait_handle != INVALID_HANDLE_VALUE) {
|
||||
+ UnregisterWait(s->load_avg_wait_handle);
|
||||
+ }
|
||||
+
|
||||
+ if (s->load_avg_event != INVALID_HANDLE_VALUE) {
|
||||
+ CloseHandle(s->load_avg_event);
|
||||
+ }
|
||||
+
|
||||
+ if (s->load_avg_pdh_query) {
|
||||
+ PdhCloseQuery(s->load_avg_pdh_query);
|
||||
+ }
|
||||
#endif
|
||||
if (s->command_state) {
|
||||
ga_command_state_cleanup_all(s->command_state);
|
||||
diff --git a/qga/meson.build b/qga/meson.build
|
||||
index 587ec4e5e8..89a4a8f713 100644
|
||||
--- a/qga/meson.build
|
||||
+++ b/qga/meson.build
|
||||
@@ -95,7 +95,7 @@ gen_tlb = []
|
||||
qga_libs = []
|
||||
if host_os == 'windows'
|
||||
qga_libs += ['-lws2_32', '-lwinmm', '-lpowrprof', '-lwtsapi32', '-lwininet', '-liphlpapi', '-lnetapi32',
|
||||
- '-lsetupapi', '-lcfgmgr32', '-luserenv']
|
||||
+ '-lsetupapi', '-lcfgmgr32', '-luserenv', '-lpdh' ]
|
||||
if have_qga_vss
|
||||
qga_libs += ['-lole32', '-loleaut32', '-lshlwapi', '-lstdc++', '-Wl,--enable-stdcall-fixup']
|
||||
subdir('vss-win32')
|
||||
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
|
||||
index 995594aaf4..e96a4b7957 100644
|
||||
--- a/qga/qapi-schema.json
|
||||
+++ b/qga/qapi-schema.json
|
||||
@@ -1863,7 +1863,7 @@
|
||||
'load5m': 'number',
|
||||
'load15m': 'number'
|
||||
},
|
||||
- 'if': 'CONFIG_GETLOADAVG'
|
||||
+ 'if': { 'any': ['CONFIG_WIN32', 'CONFIG_GETLOADAVG'] }
|
||||
}
|
||||
|
||||
##
|
||||
@@ -1871,13 +1871,18 @@
|
||||
#
|
||||
# Retrieve CPU process load information
|
||||
#
|
||||
+# .. note:: Windows does not have load average API, so QGA emulates it by
|
||||
+# calculating the average CPU usage in the last 1, 5, 15 minutes
|
||||
+# similar as Linux does this.
|
||||
+# Calculation starts from the first time this command is called.
|
||||
+#
|
||||
# Returns: load information
|
||||
#
|
||||
# Since: 10.0
|
||||
##
|
||||
{ 'command': 'guest-get-load',
|
||||
'returns': 'GuestLoadAverage',
|
||||
- 'if': 'CONFIG_GETLOADAVG'
|
||||
+ 'if': { 'any': ['CONFIG_WIN32', 'CONFIG_GETLOADAVG'] }
|
||||
}
|
||||
|
||||
##
|
||||
--
|
||||
2.48.1
|
||||
|
||||
From git@z Thu Jan 1 00:00:00 1970
|
||||
Subject: [PATCH v2 2/2] qga: Add tests for guest-get-load command
|
||||
From: Konstantin Kostiuk <kkostiuk@redhat.com>
|
||||
Date: Mon, 24 Mar 2025 15:17:29 +0200
|
||||
Message-Id: <20250324131729.70992-3-kkostiuk@redhat.com>
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
Content-Transfer-Encoding: 7bit
|
||||
|
||||
Tested-by: Dehan Meng <demeng@redhat.com>
|
||||
Reviewed-by: Yan Vugenfirer <yvugenfi@redhat.com>
|
||||
Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
|
||||
---
|
||||
tests/unit/test-qga.c | 17 +++++++++++++++++
|
||||
1 file changed, 17 insertions(+)
|
||||
|
||||
diff --git a/tests/unit/test-qga.c b/tests/unit/test-qga.c
|
||||
index 541b08a5e7..587e30c7e4 100644
|
||||
--- a/tests/unit/test-qga.c
|
||||
+++ b/tests/unit/test-qga.c
|
||||
@@ -332,6 +332,22 @@ static void test_qga_get_fsinfo(gconstpointer fix)
|
||||
}
|
||||
}
|
||||
|
||||
+static void test_qga_get_load(gconstpointer fix)
|
||||
+{
|
||||
+ const TestFixture *fixture = fix;
|
||||
+ g_autoptr(QDict) ret = NULL;
|
||||
+ QDict *load;
|
||||
+
|
||||
+ ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-load'}");
|
||||
+ g_assert_nonnull(ret);
|
||||
+ qmp_assert_no_error(ret);
|
||||
+
|
||||
+ load = qdict_get_qdict(ret, "return");
|
||||
+ g_assert(qdict_haskey(load, "load1m"));
|
||||
+ g_assert(qdict_haskey(load, "load5m"));
|
||||
+ g_assert(qdict_haskey(load, "load15m"));
|
||||
+}
|
||||
+
|
||||
static void test_qga_get_memory_block_info(gconstpointer fix)
|
||||
{
|
||||
const TestFixture *fixture = fix;
|
||||
@@ -1105,6 +1121,7 @@ int main(int argc, char **argv)
|
||||
g_test_add_data_func("/qga/get-vcpus", &fix, test_qga_get_vcpus);
|
||||
}
|
||||
g_test_add_data_func("/qga/get-fsinfo", &fix, test_qga_get_fsinfo);
|
||||
+ g_test_add_data_func("/qga/get-load", &fix, test_qga_get_load);
|
||||
g_test_add_data_func("/qga/get-memory-block-info", &fix,
|
||||
test_qga_get_memory_block_info);
|
||||
g_test_add_data_func("/qga/get-memory-blocks", &fix,
|
||||
--
|
||||
2.48.1
|
||||
|
Loading…
Reference in New Issue
Block a user