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 | 32 ++++++++++++++++++- src/qemu/qemu_monitor_text.c | 73 ++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_text.h | 3 ++ 3 files changed, 107 insertions(+), 1 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index dbf0926..298b236 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -5563,6 +5563,36 @@ qemudDomainInterfaceStats (virDomainPtr dom, #endif static int +qemudDomainMemoryStats (virDomainPtr dom, + struct _virDomainMemoryStat *stats, + unsigned int nr_stats) +{ + struct qemud_driver *driver = dom->conn->privateData; + virDomainObjPtr vm; + unsigned int nr_stats_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)) + nr_stats_ret = qemuMonitorGetMemoryStats(vm, stats, nr_stats); + +cleanup: + if (vm) + virDomainObjUnlock(vm); + return nr_stats_ret; +} + +static int qemudDomainBlockPeek (virDomainPtr dom, const char *path, unsigned long long offset, size_t size, @@ -7124,7 +7154,7 @@ static virDriver qemuDriver = { NULL, /* domainMigrateFinish */ qemudDomainBlockStats, /* domainBlockStats */ qemudDomainInterfaceStats, /* domainInterfaceStats */ - NULL, /* domainMemoryStats */ + qemudDomainMemoryStats, /* domainMemoryStats */ qemudDomainBlockPeek, /* domainBlockPeek */ qemudDomainMemoryPeek, /* domainMemoryPeek */ nodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */ diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 66526dc..4482420 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -650,6 +650,54 @@ error: return 0; } +static int parseMemoryStat(const char *vm_name, char **text, unsigned int tag, + const char *search, virDomainMemoryStatPtr stat) +{ + char *dummy; + if (STRPREFIX (*text, search)) { + *text += strlen(search); + if (virStrToLong_ull (*text, &dummy, 10, &stat->val)) { + DEBUG ("%s: error reading %s: %s", vm_name, search, *text); + return 0; + } + stat->tag = tag; + return 1; + } + return 0; +} + +/* The reply from the 'info balloon' command may contain additional memory + * statistics in the form: '[,<tag>=<val>]*' + */ +static int qemuMonitorParseExtraBalloonInfo(const virDomainObjPtr vm, + char *text, + virDomainMemoryStatPtr stats, + unsigned int nr_stats) +{ + char *p = text; + unsigned int nr_stats_found = 0; + + while (*p && nr_stats_found < nr_stats) { + if (parseMemoryStat(vm->def->name, &p, VIR_MEMSTAT_SWAP_IN, + ",mem_swapped_in=", &stats[nr_stats_found]) || + parseMemoryStat(vm->def->name, &p, VIR_MEMSTAT_SWAP_OUT, + ",mem_swapped_out=", &stats[nr_stats_found]) || + parseMemoryStat(vm->def->name, &p, VIR_MEMSTAT_MAJOR_FAULT, + ",major_page_faults=", &stats[nr_stats_found]) || + parseMemoryStat(vm->def->name, &p, VIR_MEMSTAT_MINOR_FAULT, + ",minor_page_faults=", &stats[nr_stats_found]) || + parseMemoryStat(vm->def->name, &p, VIR_MEMSTAT_MEM_FREE, + ",free_mem=", &stats[nr_stats_found]) || + parseMemoryStat(vm->def->name, &p, VIR_MEMSTAT_MEM_TOTAL, + ",total_mem=", &stats[nr_stats_found])) + nr_stats_found++; + + /* Skip to the next label */ + p = strchr (p, ','); + if (!p) break; + } + return nr_stats_found; +} /* The reply from QEMU contains 'ballon: actual=421' where value is in MB */ @@ -697,6 +745,31 @@ cleanup: return ret; } +int qemuMonitorGetMemoryStats(const virDomainObjPtr vm, + virDomainMemoryStatPtr stats, + unsigned int nr_stats) +{ + char *reply = NULL; + int ret = 0; + char *offset; + + DEBUG("vm=%p, pid=%d, id=%d, name=%s", vm, vm->pid, vm->def->id, vm->def->name); + + if (qemuMonitorCommand(vm, "info balloon", &reply) < 0) { + qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED, + "%s", _("could not query memory balloon allocation")); + return -1; + } + + if ((offset = strstr(reply, BALLOON_PREFIX)) != NULL) { + offset = strchr(reply, ','); + ret = qemuMonitorParseExtraBalloonInfo(vm, offset, stats, nr_stats); + } + + VIR_FREE(reply); + return ret; +} + int qemuMonitorGetBlockStatsInfo(const virDomainObjPtr vm, const char *devname, diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index 9175456..0181c08 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -42,6 +42,9 @@ int qemuMonitorGetCPUInfo(const virDomainObjPtr vm, int **pids); int qemuMonitorGetBalloonInfo(const virDomainObjPtr vm, unsigned long *currmem); +int qemuMonitorGetMemoryStats(const virDomainObjPtr vm, + virDomainMemoryStatPtr stats, + unsigned int nr_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