Since this is already in QEMU we can add this stat which might be useful for people. Resolves: https://issues.redhat.com/browse/RHEL-71883 Signed-off-by: Martin Kletzander <mkletzan@xxxxxxxxxx> --- docs/manpages/virsh.rst | 3 +++ src/libvirt-domain.c | 3 +++ src/qemu/qemu_agent.c | 59 +++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_agent.h | 6 +++++ src/qemu/qemu_driver.c | 32 ++++++++++++++++++++++ tests/qemuagenttest.c | 53 ++++++++++++++++++++++++++++++++++++ 6 files changed, 156 insertions(+) diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst index 06c2802b3f9f..60b556cb0cd0 100644 --- a/docs/manpages/virsh.rst +++ b/docs/manpages/virsh.rst @@ -2408,6 +2408,9 @@ When selecting the *--state* group the following fields are returned: for bank <index> in cache monitor <num> * ``cpu.cache.monitor.<num>.bank.<index>.bytes`` - the number of bytes of last level cache that the domain is using on cache bank <index> +* ``cpu.load.1m`` - average load in guest for last 1 minute +* ``cpu.load.5m`` - average load in guest for last 5 minutes +* ``cpu.load.15m`` - average load in guest for last 15 minutes *--balloon* returns: diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c index 072cc3225579..35f5e926e52b 100644 --- a/src/libvirt-domain.c +++ b/src/libvirt-domain.c @@ -12272,6 +12272,9 @@ virConnectGetDomainCapabilities(virConnectPtr conn, * last level cache that the * domain is using on cache * bank <index> + * "cpu.load.1m" - average load in guest for last 1 minute + * "cpu.load.5m" - average load in guest for last 5 minutes + * "cpu.load.15m" - average load in guest for last 15 minutes * * VIR_DOMAIN_STATS_BALLOON: * Return memory balloon device information. diff --git a/src/qemu/qemu_agent.c b/src/qemu/qemu_agent.c index 43fca86f10ed..6dbe8c52d738 100644 --- a/src/qemu/qemu_agent.c +++ b/src/qemu/qemu_agent.c @@ -2568,3 +2568,62 @@ int qemuAgentGetDisks(qemuAgent *agent, g_free(*disks); return -1; } + + +int +qemuAgentGetLoadAvg(qemuAgent *agent, + double *load1m, + double *load5m, + double *load15m, + bool report_unsupported) +{ + g_autoptr(virJSONValue) cmd = NULL; + g_autoptr(virJSONValue) reply = NULL; + virJSONValue *data = NULL; + int rc; + + if (load1m) + *load1m = 0; + + if (load5m) + *load5m = 0; + + if (load15m) + *load15m = 0; + + if (!(cmd = qemuAgentMakeCommand("guest-get-load", NULL))) + return -1; + + if ((rc = qemuAgentCommandFull(agent, cmd, &reply, agent->timeout, + report_unsupported)) < 0) + return rc; + + if (!(data = virJSONValueObjectGetObject(reply, "return"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("qemu agent didn't return an array of loads")); + return -1; + } + + if (load1m && + virJSONValueObjectGetNumberDouble(data, "load1m", load1m) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("'load1m' missing in reply of guest-get-load")); + return -1; + } + + if (load5m && + virJSONValueObjectGetNumberDouble(data, "load5m", load5m) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("'load5m' missing in reply of guest-get-load")); + return -1; + } + + if (load15m && + virJSONValueObjectGetNumberDouble(data, "load15m", load15m) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("'load15m' missing in reply of guest-get-load")); + return -1; + } + + return 0; +} diff --git a/src/qemu/qemu_agent.h b/src/qemu/qemu_agent.h index f98586e8f8ab..cd17a98d3924 100644 --- a/src/qemu/qemu_agent.h +++ b/src/qemu/qemu_agent.h @@ -195,3 +195,9 @@ int qemuAgentSSHRemoveAuthorizedKeys(qemuAgent *agent, int qemuAgentGetDisks(qemuAgent *mon, qemuAgentDiskInfo ***disks, bool report_unsupported); + +int qemuAgentGetLoadAvg(qemuAgent *agent, + double *load1m, + double *load5m, + double *load15m, + bool report_unsupported); diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 80c918312b8f..d9279b3a5804 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -16937,6 +16937,36 @@ qemuDomainGetStatsCpuHaltPollTime(virDomainObj *dom, return; } + +static void +qemuDomainGetStatsCpuLoadAvg(virDomainObj *dom, + virTypedParamList *params, + unsigned int privflags) +{ + qemuAgent *agent = NULL; + double load1m = 0; + double load5m = 0; + double load15m = 0; + int rc = 0; + + if (!HAVE_JOB(privflags) || + !virDomainObjIsActive(dom) || + !qemuDomainAgentAvailable(dom, false)) + return; + + agent = qemuDomainObjEnterAgent(dom); + rc = qemuAgentGetLoadAvg(agent, &load1m, &load5m, &load15m, false); + qemuDomainObjExitAgent(dom, agent); + + if (rc < 0) + return; + + virTypedParamListAddDouble(params, load1m, "cpu.load.1m"); + virTypedParamListAddDouble(params, load5m, "cpu.load.5m"); + virTypedParamListAddDouble(params, load15m, "cpu.load.15m"); +} + + static void qemuDomainGetStatsCpu(virQEMUDriver *driver, virDomainObj *dom, @@ -16954,6 +16984,8 @@ qemuDomainGetStatsCpu(virQEMUDriver *driver, qemuDomainGetStatsCpuCache(driver, dom, params); qemuDomainGetStatsCpuHaltPollTime(dom, params, privflags); + + qemuDomainGetStatsCpuLoadAvg(dom, params, privflags); } diff --git a/tests/qemuagenttest.c b/tests/qemuagenttest.c index 328788024197..566571cf1107 100644 --- a/tests/qemuagenttest.c +++ b/tests/qemuagenttest.c @@ -1356,6 +1356,58 @@ testQemuAgentTimezone(const void *data) virTypedParamsFree(params, nparams); return ret; } + + +static const char testQemuAgentGetLoadAvgResponse[] = + "{" + " \"return\": {" + " \"load15m\": 0.03564453125," + " \"load5m\": 0.064453125," + " \"load1m\": 0.00390625" + " }" + "}"; + +static int +testQemuAgentGetLoadAvg(const void *data) +{ + virDomainXMLOption *xmlopt = (virDomainXMLOption *)data; + g_autoptr(qemuMonitorTest) test = qemuMonitorTestNewAgent(xmlopt); + double load1m = 0; + double load5m = 0; + double load15m = 0; + + if (!test) + return -1; + + if (qemuMonitorTestAddAgentSyncResponse(test) < 0) + return -1; + + if (qemuMonitorTestAddItem(test, "guest-get-load", + testQemuAgentGetLoadAvgResponse) < 0) + return -1; + + if (qemuAgentGetLoadAvg(qemuMonitorTestGetAgent(test), + &load1m, &load5m, &load15m, true) < 0) + return -1; + +#define VALIDATE_LOAD(value_, expected_) \ + do { \ + if (value_ != expected_) { \ + virReportError(VIR_ERR_INTERNAL_ERROR, \ + "Expected " #value_ " '%.11f', got '%.11f'", \ + expected_, value_); \ + return -1; \ + } \ + } while (0) + + VALIDATE_LOAD(load1m, 0.00390625); + VALIDATE_LOAD(load5m, 0.064453125); + VALIDATE_LOAD(load15m, 0.03564453125); + + return 0; +} + + static int mymain(void) { @@ -1392,6 +1444,7 @@ mymain(void) DO_TEST(Timezone); DO_TEST(SSHKeys); DO_TEST(GetDisks); + DO_TEST(GetLoadAvg); DO_TEST(Timeout); /* Timeout should always be called last */ -- 2.48.1