[libvirt] [PATCH v2 06/10] Add capability to fetch balloon stats

John Ferlan jferlan at redhat.com
Mon Jul 8 19:20:32 UTC 2013


This patch will add the QEMU_MONITOR_OBJECT_PROPERTY_BALLOON_STATS type and
a mechanism in the qemuMonitorObjectProperty to fetch and store an opaque
data array assuming that we are provided a count of current elements,
a count of maximum elements, and the address of the array store the data.
Use the mechanism to fetch balloon driver statistics.
---
 src/qemu/qemu_monitor.c      |   3 +-
 src/qemu/qemu_monitor_json.c | 206 ++++++++++++++++++++-----------------------
 src/qemu/qemu_monitor_json.h |   5 ++
 3 files changed, 103 insertions(+), 111 deletions(-)

diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 038c9e8..aac2692 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -1489,7 +1489,8 @@ int qemuMonitorGetMemoryStats(qemuMonitorPtr mon,
     }
 
     if (mon->json)
-        ret = qemuMonitorJSONGetMemoryStats(mon, stats, nr_stats);
+        ret = qemuMonitorJSONGetMemoryStats(mon, mon->balloonpath,
+                                            stats, nr_stats);
     else
         ret = qemuMonitorTextGetMemoryStats(mon, stats, nr_stats);
     return ret;
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 2d7f9b6..1bc9b71 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -1368,129 +1368,111 @@ cleanup:
 }
 
 
-int qemuMonitorJSONGetMemoryStats(qemuMonitorPtr mon,
-                                  virDomainMemoryStatPtr stats,
-                                  unsigned int nr_stats)
-{
-    int ret;
-    int got = 0;
-    virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-balloon",
-                                                     NULL);
-    virJSONValuePtr reply = NULL;
+/* Process the balloon driver statistics.  The request and data returned
+ * will be as follows (although the 'child[#]' entry will differ based on
+ * where it's run).
+ *
+ * { "execute": "qom-get","arguments": \
+ *    { "path": "/machine/i440fx/pci.0/child[7]","property": "guest-stats"} }
+ *
+ * {"return": {"stats": \
+ *               {"stat-swap-out": 0,
+ *                "stat-free-memory": 686350336,
+ *                "stat-minor-faults": 697283,
+ *                "stat-major-faults": 951,
+ *                "stat-total-memory": 1019924480,
+ *                "stat-swap-in": 0},
+ *            "last-update": 1371221540}}
+ *
+ * A value in "stats" can be -1 indicating it's never been collected/stored.
+ * The 'last-update' value could be used in the future in order to determine
+ * rates and/or whether data has been collected since a previous cycle.
+ * It's currently unused.
+ */
+#define GET_BALLOON_STATS(FIELD, TAG, DIVISOR)                                \
+    if (virJSONValueObjectHasKey(statsdata, FIELD) &&                         \
+       (prop->curelems < prop->maxelems)) {                                   \
+        if (virJSONValueObjectGetNumberUlong(statsdata, FIELD, &mem) < 0) {   \
+            VIR_DEBUG("Failed to get '%s' value", FIELD);                     \
+        } else {                                                              \
+            /* Not being collected? No point in providing bad data */         \
+            if (mem != -1UL) {                                                \
+                stat[prop->curelems].tag = TAG;                               \
+                stat[prop->curelems].val = mem / DIVISOR;                     \
+                prop->curelems++;                                             \
+            }                                                                 \
+        }                                                                     \
+    }
 
-    if (!cmd)
-        return -1;
+static int
+qemuMonitorJSONGetBalloonStats(virJSONValuePtr data,
+                               qemuMonitorJSONObjectPropertyPtr prop)
+{
+    int ret = -1;
+    unsigned long long mem;
+    virJSONValuePtr statsdata;
+    virDomainMemoryStatPtr stat = (virDomainMemoryStatPtr)prop->val.ptr;
 
-    ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+    VIR_DEBUG("Address of found stat = %p", stat);
 
-    if (ret == 0) {
-        /* See if balloon soft-failed */
-        if (qemuMonitorJSONHasError(reply, "DeviceNotActive") ||
-            qemuMonitorJSONHasError(reply, "KVMMissingCap"))
-            goto cleanup;
+    if (!(statsdata = virJSONValueObjectGet(data, "stats"))) {
+        VIR_DEBUG("data does not include 'stats'");
+        goto cleanup;
+    }
 
-        /* See if any other fatal error occurred */
-        ret = qemuMonitorJSONCheckError(cmd, reply);
+    GET_BALLOON_STATS("stat-swap-in",
+                      VIR_DOMAIN_MEMORY_STAT_SWAP_IN, 1024);
+    GET_BALLOON_STATS("stat-swap-out",
+                      VIR_DOMAIN_MEMORY_STAT_SWAP_OUT, 1024);
+    GET_BALLOON_STATS("stat-major-faults",
+                      VIR_DOMAIN_MEMORY_STAT_MAJOR_FAULT, 1);
+    GET_BALLOON_STATS("stat-minor-faults",
+                      VIR_DOMAIN_MEMORY_STAT_MINOR_FAULT, 1);
+    GET_BALLOON_STATS("stat-free-memory",
+                      VIR_DOMAIN_MEMORY_STAT_UNUSED, 1024);
+    GET_BALLOON_STATS("stat-total-memory",
+                      VIR_DOMAIN_MEMORY_STAT_AVAILABLE, 1024);
 
-        /* Success */
-        if (ret == 0) {
-            virJSONValuePtr data;
-            unsigned long long mem;
+    ret = 0;
 
-            if (!(data = virJSONValueObjectGet(reply, "return"))) {
-                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                               _("info balloon reply was missing return data"));
-                ret = -1;
-                goto cleanup;
-            }
+cleanup:
+    virJSONValueFree(statsdata);
+    return ret;
+}
+#undef GET_BALLOON_STATS
 
-            if (virJSONValueObjectHasKey(data, "actual") && (got < nr_stats)) {
-                if (virJSONValueObjectGetNumberUlong(data, "actual", &mem) < 0) {
-                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                                   _("info balloon reply was missing balloon actual"));
-                    ret = -1;
-                    goto cleanup;
-                }
-                stats[got].tag = VIR_DOMAIN_MEMORY_STAT_ACTUAL_BALLOON;
-                stats[got].val = (mem/1024);
-                got++;
-            }
+int qemuMonitorJSONGetMemoryStats(qemuMonitorPtr mon,
+                                  char *balloonpath,
+                                  virDomainMemoryStatPtr stats,
+                                  unsigned int nr_stats)
+{
+    int ret;
+    unsigned long long actualmem;
+    int got = 0;
+    qemuMonitorJSONObjectProperty prop;
 
-            if (virJSONValueObjectHasKey(data, "mem_swapped_in") && (got < nr_stats)) {
-                if (virJSONValueObjectGetNumberUlong(data, "mem_swapped_in", &mem) < 0) {
-                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                                   _("info balloon reply was missing balloon mem_swapped_in"));
-                    ret = -1;
-                    goto cleanup;
-                }
-                stats[got].tag = VIR_DOMAIN_MEMORY_STAT_SWAP_IN;
-                stats[got].val = (mem/1024);
-                got++;
-            }
-            if (virJSONValueObjectHasKey(data, "mem_swapped_out") && (got < nr_stats)) {
-                if (virJSONValueObjectGetNumberUlong(data, "mem_swapped_out", &mem) < 0) {
-                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                                   _("info balloon reply was missing balloon mem_swapped_out"));
-                    ret = -1;
-                    goto cleanup;
-                }
-                stats[got].tag = VIR_DOMAIN_MEMORY_STAT_SWAP_OUT;
-                stats[got].val = (mem/1024);
-                got++;
-            }
-            if (virJSONValueObjectHasKey(data, "major_page_faults") && (got < nr_stats)) {
-                if (virJSONValueObjectGetNumberUlong(data, "major_page_faults", &mem) < 0) {
-                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                                   _("info balloon reply was missing balloon major_page_faults"));
-                    ret = -1;
-                    goto cleanup;
-                }
-                stats[got].tag = VIR_DOMAIN_MEMORY_STAT_MAJOR_FAULT;
-                stats[got].val = mem;
-                got++;
-            }
-            if (virJSONValueObjectHasKey(data, "minor_page_faults") && (got < nr_stats)) {
-                if (virJSONValueObjectGetNumberUlong(data, "minor_page_faults", &mem) < 0) {
-                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                                   _("info balloon reply was missing balloon minor_page_faults"));
-                    ret = -1;
-                    goto cleanup;
-                }
-                stats[got].tag = VIR_DOMAIN_MEMORY_STAT_MINOR_FAULT;
-                stats[got].val = mem;
-                got++;
-            }
-            if (virJSONValueObjectHasKey(data, "free_mem") && (got < nr_stats)) {
-                if (virJSONValueObjectGetNumberUlong(data, "free_mem", &mem) < 0) {
-                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                                   _("info balloon reply was missing balloon free_mem"));
-                    ret = -1;
-                    goto cleanup;
-                }
-                stats[got].tag = VIR_DOMAIN_MEMORY_STAT_UNUSED;
-                stats[got].val = (mem/1024);
-                got++;
-            }
-            if (virJSONValueObjectHasKey(data, "total_mem") && (got < nr_stats)) {
-                if (virJSONValueObjectGetNumberUlong(data, "total_mem", &mem) < 0) {
-                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                                   _("info balloon reply was missing balloon total_mem"));
-                    ret = -1;
-                    goto cleanup;
-                }
-                stats[got].tag = VIR_DOMAIN_MEMORY_STAT_AVAILABLE;
-                stats[got].val = (mem/1024);
-                got++;
-            }
+    ret = qemuMonitorJSONGetBalloonInfo(mon, &actualmem);
+    if (ret == 1 && (got < nr_stats)) {
+        stats[got].tag = VIR_DOMAIN_MEMORY_STAT_ACTUAL_BALLOON;
+        stats[got].val = actualmem;
+        got++;
+    }
+
+    if (got == 1 && balloonpath) {
+        memset(&prop, 0, sizeof(qemuMonitorJSONObjectProperty));
+        prop.type = QEMU_MONITOR_OBJECT_PROPERTY_BALLOON_STATS;
+        prop.curelems = got;
+        prop.maxelems = nr_stats;
+        prop.val.ptr = (void **)stats;
+        if (qemuMonitorJSONGetObjectProperty(mon, balloonpath,
+                                             "guest-stats", &prop) == 0) {
+            got = prop.curelems;
         }
     }
 
     if (got > 0)
         ret = got;
 
-cleanup:
-    virJSONValueFree(cmd);
-    virJSONValueFree(reply);
     return ret;
 }
 
@@ -4747,6 +4729,9 @@ int qemuMonitorJSONGetObjectProperty(qemuMonitorPtr mon,
         if (tmp)
             ret = 0;
         break;
+    case QEMU_MONITOR_OBJECT_PROPERTY_BALLOON_STATS:
+        ret = qemuMonitorJSONGetBalloonStats(data, prop);
+        break;
     case QEMU_MONITOR_OBJECT_PROPERTY_LAST:
     default:
         virReportError(VIR_ERR_INTERNAL_ERROR,
@@ -4810,6 +4795,7 @@ int qemuMonitorJSONSetObjectProperty(qemuMonitorPtr mon,
     case QEMU_MONITOR_OBJECT_PROPERTY_STRING:
         MAKE_SET_CMD("s:value", prop->val.str);
         break;
+    case QEMU_MONITOR_OBJECT_PROPERTY_BALLOON_STATS:
     case QEMU_MONITOR_OBJECT_PROPERTY_LAST:
     default:
         virReportError(VIR_ERR_INTERNAL_ERROR,
@@ -4830,7 +4816,7 @@ cleanup:
 
     return ret;
 }
-
+#undef MAKE_SET_CMD
 
 int qemuMonitorJSONGetObjectProps(qemuMonitorPtr mon,
                                   const char *type,
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index b0068ff..b3945b2 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -59,6 +59,7 @@ int qemuMonitorJSONGetVirtType(qemuMonitorPtr mon,
 int qemuMonitorJSONGetBalloonInfo(qemuMonitorPtr mon,
                                   unsigned long long *currmem);
 int qemuMonitorJSONGetMemoryStats(qemuMonitorPtr mon,
+                                  char *balloonpath,
                                   virDomainMemoryStatPtr stats,
                                   unsigned int nr_stats);
 int qemuMonitorJSONSetMemoryStatsPeriod(qemuMonitorPtr mon,
@@ -360,6 +361,7 @@ typedef enum {
     QEMU_MONITOR_OBJECT_PROPERTY_ULONG,
     QEMU_MONITOR_OBJECT_PROPERTY_DOUBLE,
     QEMU_MONITOR_OBJECT_PROPERTY_STRING,
+    QEMU_MONITOR_OBJECT_PROPERTY_BALLOON_STATS,
 
     QEMU_MONITOR_OBJECT_PROPERTY_LAST
 } qemuMonitorJSONObjectPropertyType;
@@ -368,6 +370,8 @@ typedef struct _qemuMonitorJSONObjectProperty qemuMonitorJSONObjectProperty;
 typedef qemuMonitorJSONObjectProperty *qemuMonitorJSONObjectPropertyPtr;
 struct _qemuMonitorJSONObjectProperty {
     int type;    /* qemuMonitorJSONObjectPropertyType */
+    int curelems;   /* Current number elements in **ptr array */
+    int maxelems;   /* Maximum number elements allowed in any **ptr array */
     union {
         bool b;
         int i;
@@ -376,6 +380,7 @@ struct _qemuMonitorJSONObjectProperty {
         unsigned long long ul;
         double d;
         char *str;
+        void **ptr;
     } val;
 };
 
-- 
1.8.1.4




More information about the libvir-list mailing list