[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH 3/6] qemu-driver: Enable domainMemStats in the qemu driver



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
components will be reported.

Signed-off-by: Adam Litke <agl us ibm com>
To: Daniel Veillard <veillard redhat com>
Cc: Daniel P. Berrange <berrange redhat com>
Cc: libvirt list <libvir-list redhat com>
---
 src/qemu/qemu_driver.c       |   39 +++++++++++++++++++-
 src/qemu/qemu_monitor_text.c |   83 ++++++++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_monitor_text.h |    3 ++
 3 files changed, 124 insertions(+), 1 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 1ddc23e..562a20b 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -6235,6 +6235,43 @@ 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 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 (virDomainObjIsActive(vm)) {
+        qemuDomainObjPrivatePtr priv = vm->privateData;
+        qemuDomainObjEnterMonitor(vm);
+        ret = qemuMonitorTextGetMemoryStats(priv->mon, stats, nr_stats);
+        qemuDomainObjExitMonitor(vm);
+    } else {
+        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
+                         "%s", _("domain is not running"));
+    }
+
+cleanup:
+    if (vm)
+        virDomainObjUnlock(vm);
+    return ret;
+}
+
+static int
 qemudDomainBlockPeek (virDomainPtr dom,
                       const char *path,
                       unsigned long long offset, size_t size,
@@ -7907,7 +7944,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 0cb9ea6..ab361c6 100644
--- a/src/qemu/qemu_monitor_text.c
+++ b/src/qemu/qemu_monitor_text.c
@@ -454,6 +454,65 @@ error:
     return 0;
 }
 
+static int parseMemoryStat(char **text, unsigned int tag,
+                           const char *search, virDomainMemoryStatPtr stat)
+{
+    char *dummy;
+    unsigned long long value;
+
+    if (STRPREFIX (*text, search)) {
+        *text += strlen(search);
+        if (virStrToLong_ull (*text, &dummy, 10, &value)) {
+            DEBUG ("error reading %s: %s", search, *text);
+            return 0;
+        }
+
+        /* Convert bytes to kilobytes for libvirt */
+        switch (tag) {
+            case VIR_DOMAIN_MEMORY_STAT_SWAP_IN:
+            case VIR_DOMAIN_MEMORY_STAT_SWAP_OUT:
+            case VIR_DOMAIN_MEMORY_STAT_UNUSED:
+            case VIR_DOMAIN_MEMORY_STAT_AVAILABLE:
+                value = value >> 10;
+        }
+        stat->tag = tag;
+        stat->val = value;
+        return 1;
+    }
+    return 0;
+}
+
+/* The reply from the 'info balloon' command may contain additional memory
+ * statistics in the form: '[,<tag>=<val>]*'
+ */
+static int qemuMonitorParseExtraBalloonInfo(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(&p, VIR_DOMAIN_MEMORY_STAT_SWAP_IN,
+                            ",mem_swapped_in=", &stats[nr_stats_found]) ||
+            parseMemoryStat(&p, VIR_DOMAIN_MEMORY_STAT_SWAP_OUT,
+                            ",mem_swapped_out=", &stats[nr_stats_found]) ||
+            parseMemoryStat(&p, VIR_DOMAIN_MEMORY_STAT_MAJOR_FAULT,
+                            ",major_page_faults=", &stats[nr_stats_found]) ||
+            parseMemoryStat(&p, VIR_DOMAIN_MEMORY_STAT_MINOR_FAULT,
+                            ",minor_page_faults=", &stats[nr_stats_found]) ||
+            parseMemoryStat(&p, VIR_DOMAIN_MEMORY_STAT_UNUSED,
+                            ",free_mem=", &stats[nr_stats_found]) ||
+            parseMemoryStat(&p, VIR_DOMAIN_MEMORY_STAT_AVAILABLE,
+                            ",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 */
@@ -499,6 +558,30 @@ cleanup:
     return ret;
 }
 
+int qemuMonitorTextGetMemoryStats(qemuMonitorPtr mon,
+                                  virDomainMemoryStatPtr stats,
+                                  unsigned int nr_stats)
+{
+    char *reply = NULL;
+    int ret = 0;
+    char *offset;
+
+    if (qemuMonitorCommand(mon, "info balloon", &reply) < 0) {
+        qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
+                         "%s", _("could not query memory balloon statistics"));
+        return -1;
+    }
+
+    if ((offset = strstr(reply, BALLOON_PREFIX)) != NULL) {
+        if ((offset = strchr(reply, ',')) != NULL) {
+            ret = qemuMonitorParseExtraBalloonInfo(offset, stats, nr_stats);
+        }
+    }
+
+    VIR_FREE(reply);
+    return ret;
+}
+
 
 int qemuMonitorTextGetBlockStatsInfo(qemuMonitorPtr mon,
                                      const char *devname,
diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h
index 519edf4..5897a03 100644
--- a/src/qemu/qemu_monitor_text.h
+++ b/src/qemu/qemu_monitor_text.h
@@ -45,6 +45,9 @@ int qemuMonitorTextGetCPUInfo(qemuMonitorPtr mon,
                               int **pids);
 int qemuMonitorTextGetBalloonInfo(qemuMonitorPtr mon,
                                   unsigned long *currmem);
+int qemuMonitorTextGetMemoryStats(qemuMonitorPtr mon,
+                                  virDomainMemoryStatPtr stats,
+                                  unsigned int nr_stats);
 int qemuMonitorTextGetBlockStatsInfo(qemuMonitorPtr mon,
                                      const char *devname,
                                      long long *rd_req,
-- 
1.6.5


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]