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@xxxxxxxxxx> To: libvirt list <libvir-list@xxxxxxxxxx> --- 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 -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list