Support for memory statistics reporting is accepted for qemu inclusion.
Statistics are reported via the monitor command 'info balloon' as a comma
seprated list:
(qemu) info balloon
balloon:
actual=1024,mem_swapped_in=0,mem_swapped_out=0,major_page_faults=88,minor_page_faults=105535,free_mem=1017065472,total_mem=1045229568
Libvirt, qemu, and the guest operating system may support a subset of the
statistics defined by the virtio spec. Thus, only statistics recognized by all
components will be reported. All others will be returned as -1.
Signed-off-by: Adam Litke <agl(a)us.ibm.com>
To: libvirt list <libvir-list(a)redhat.com>
---
src/qemu/qemu_driver.c | 40 +++++++++++++++++++++++++++--
src/qemu/qemu_monitor_text.c | 56 ++++++++++++++++++++++++++++++++++++++++-
src/qemu/qemu_monitor_text.h | 3 +-
3 files changed, 93 insertions(+), 6 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 35c397d..60c0da1 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -3077,7 +3077,7 @@ static int qemudDomainGetInfo(virDomainPtr dom,
info->maxMem = vm->def->maxmem;
if (virDomainIsActive(vm)) {
- err = qemuMonitorGetBalloonInfo(vm, &balloon);
+ err = qemuMonitorGetBalloonInfo(vm, &balloon, NULL);
if (err < 0)
goto cleanup;
@@ -3880,7 +3880,7 @@ static char *qemudDomainDumpXML(virDomainPtr dom,
/* Refresh current memory based on balloon info */
if (virDomainIsActive(vm)) {
- err = qemuMonitorGetBalloonInfo(vm, &balloon);
+ err = qemuMonitorGetBalloonInfo(vm, &balloon, NULL);
if (err < 0)
goto cleanup;
if (err > 0)
@@ -5563,6 +5563,40 @@ qemudDomainInterfaceStats (virDomainPtr dom,
#endif
static int
+qemudDomainMemStats (virDomainPtr dom,
+ struct _virDomainMemStats *stats)
+{
+ struct qemud_driver *driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ struct _virDomainMemStats stats2 = { -1, -1, -1, -1, -1, -1 };
+ int ret = -1;
+
+ qemuDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ qemuDriverUnlock(driver);
+
+ if (!vm) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(dom->uuid, uuidstr);
+ qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
+ _("no domain with matching uuid '%s'"),
uuidstr);
+ goto cleanup;
+ }
+
+ if (virDomainIsActive(vm)) {
+ memcpy (stats, &stats2, sizeof stats);
+ ret = qemuMonitorGetBalloonInfo(vm, NULL, stats);
+ if (ret > 0)
+ ret = 0;
+ }
+
+cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ return ret;
+}
+
+static int
qemudDomainBlockPeek (virDomainPtr dom,
const char *path,
unsigned long long offset, size_t size,
@@ -7124,7 +7158,7 @@ static virDriver qemuDriver = {
NULL, /* domainMigrateFinish */
qemudDomainBlockStats, /* domainBlockStats */
qemudDomainInterfaceStats, /* domainInterfaceStats */
- NULL, /* domainMemStats */
+ qemudDomainMemStats, /* domainMemStats */
qemudDomainBlockPeek, /* domainBlockPeek */
qemudDomainMemoryPeek, /* domainMemoryPeek */
nodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c
index 66526dc..f785f7c 100644
--- a/src/qemu/qemu_monitor_text.c
+++ b/src/qemu/qemu_monitor_text.c
@@ -650,6 +650,52 @@ error:
return 0;
}
+/* The reply from the 'info balloon' command may contain additional memory
+ * statistics in the form: '[,<tag>=<val>]*'
+ */
+static void qemuMonitorParseExtraBalloonInfo(const virDomainObjPtr vm,
+ char *text,
+ virDomainMemStatsPtr stats)
+{
+ char *dummy, *p = text;
+ while (*p) {
+ if (STRPREFIX (p, ",mem_swapped_in=")) {
+ p += 16;
+ if (virStrToLong_ull (p, &dummy, 10, &stats->swap_in))
+ DEBUG ("%s: error reading mem_swapped_in: %s",
+ vm->def->name, p);
+ } else if (STRPREFIX (p, ",mem_swapped_out=")) {
+ p += 17;
+ if (virStrToLong_ull (p, &dummy, 10, &stats->swap_out))
+ DEBUG ("%s: error reading mem_swapped_out: %s",
+ vm->def->name, p);
+ } else if (STRPREFIX (p, ",major_page_faults=")) {
+ p += 19;
+ if (virStrToLong_ull (p, &dummy, 10, &stats->major_fault))
+ DEBUG ("%s: error reading major_page_faults: %s",
+ vm->def->name, p);
+ } else if (STRPREFIX (p, ",minor_page_faults=")) {
+ p += 19;
+ if (virStrToLong_ull (p, &dummy, 10, &stats->minor_fault))
+ DEBUG ("%s: error reading minor_page_faults: %s",
+ vm->def->name, p);
+ } else if (STRPREFIX (p, ",free_mem=")) {
+ p += 10;
+ if (virStrToLong_ull (p, &dummy, 10, &stats->mem_free))
+ DEBUG ("%s: error reading free_mem: %s",
+ vm->def->name, p);
+ } else if (STRPREFIX (p, ",total_mem=")) {
+ p += 11;
+ if (virStrToLong_ull (p, &dummy, 10, &stats->mem_tot))
+ DEBUG ("%s: error reading total_mem: %s",
+ vm->def->name, p);
+ }
+
+ /* Skip to the next label */
+ p = strchr (p, ',');
+ if (!p) break;
+ }
+}
/* The reply from QEMU contains 'ballon: actual=421' where value is in MB */
@@ -660,7 +706,8 @@ error:
* or -1 on failure
*/
int qemuMonitorGetBalloonInfo(const virDomainObjPtr vm,
- unsigned long *currmem)
+ unsigned long *currmem,
+ virDomainMemStatsPtr stats)
{
char *reply = NULL;
int ret = -1;
@@ -683,7 +730,12 @@ int qemuMonitorGetBalloonInfo(const virDomainObjPtr vm,
_("could not parse memory balloon allocation from
'%s'"), reply);
goto cleanup;
}
- *currmem = memMB * 1024;
+ if (currmem != NULL)
+ *currmem = memMB * 1024;
+ offset = strchr(reply, ',');
+ if (stats != NULL && offset != NULL) {
+ qemuMonitorParseExtraBalloonInfo(vm, offset, stats);
+ }
ret = 1;
} else {
/* We don't raise an error here, since its to be expected that
diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h
index 9175456..4e9b581 100644
--- a/src/qemu/qemu_monitor_text.h
+++ b/src/qemu/qemu_monitor_text.h
@@ -41,7 +41,8 @@ int qemuMonitorSystemPowerdown(const virDomainObjPtr vm);
int qemuMonitorGetCPUInfo(const virDomainObjPtr vm,
int **pids);
int qemuMonitorGetBalloonInfo(const virDomainObjPtr vm,
- unsigned long *currmem);
+ unsigned long *currmem,
+ virDomainMemStatsPtr stats);
int qemuMonitorGetBlockStatsInfo(const virDomainObjPtr vm,
const char *devname,
long long *rd_req,
--
1.6.5