]> xenbits.xensource.com Git - people/liuw/libxenctrl-split/libvirt.git/commitdiff
Add capability to fetch balloon stats
authorJohn Ferlan <jferlan@redhat.com>
Thu, 11 Jul 2013 23:18:48 +0000 (19:18 -0400)
committerJohn Ferlan <jferlan@redhat.com>
Tue, 16 Jul 2013 12:44:52 +0000 (08:44 -0400)
This patch will add the qemuMonitorJSONGetMemoryStats() to execute a
"guest-stats" on the balloonpath using "get-qom" replacing the former
mechanism which looked through the "query-ballon" returned data for
the fields.  The "query-balloon" code only returns 'actual' memory.
Rather than duplicating the existing code, have the JSON API use the
GetBalloonInfo API.

A check in the qemuMonitorGetMemoryStats() will be made to ensure the
balloon driver path has been set.  Since the underlying JSON code can
return data not associated with the balloon driver, we don't fail on
a failure to get the balloonpath.  Of course since we've made the check,
we can then set the ballooninit flag.  Getting the path here is primarily
due to the process reconnect path which doesn't attempt to set the
collection period.

src/qemu/qemu_monitor.c
src/qemu/qemu_monitor_json.c
src/qemu/qemu_monitor_json.h

index 82d59591c8e324aa39dcc702f1f19d04daf11108..b3880a98e114c27d32d96120978604552d4d6895 100644 (file)
@@ -1491,10 +1491,14 @@ int qemuMonitorGetMemoryStats(qemuMonitorPtr mon,
         return -1;
     }
 
-    if (mon->json)
-        ret = qemuMonitorJSONGetMemoryStats(mon, stats, nr_stats);
-    else
+    if (mon->json) {
+        ignore_value(qemuMonitorFindBalloonObjectPath(mon, mon->vm, "/"));
+        mon->ballooninit = true;
+        ret = qemuMonitorJSONGetMemoryStats(mon, mon->balloonpath,
+                                            stats, nr_stats);
+    } else {
         ret = qemuMonitorTextGetMemoryStats(mon, stats, nr_stats);
+    }
     return ret;
 }
 
index 40e1de412d10c6c5306bf2b69c6a998cf351f092..fb84c03c79c3167172722d9d4426dfe333dc7f35 100644 (file)
@@ -1361,131 +1361,115 @@ cleanup:
 }
 
 
+/* 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) &&                         \
+       (got < nr_stats)) {                                                    \
+        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) {                                                \
+                stats[got].tag = TAG;                                         \
+                stats[got].val = mem / DIVISOR;                               \
+                got++;                                                        \
+            }                                                                 \
+        }                                                                     \
+    }
+
+
 int qemuMonitorJSONGetMemoryStats(qemuMonitorPtr mon,
+                                  char *balloonpath,
                                   virDomainMemoryStatPtr stats,
                                   unsigned int nr_stats)
 {
     int ret;
-    int got = 0;
-    virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-balloon",
-                                                     NULL);
+    virJSONValuePtr cmd = NULL;
     virJSONValuePtr reply = NULL;
+    virJSONValuePtr data;
+    virJSONValuePtr statsdata;
+    unsigned long long mem;
+    int got = 0;
 
-    if (!cmd)
-        return -1;
+    ret = qemuMonitorJSONGetBalloonInfo(mon, &mem);
+    if (ret == 1 && (got < nr_stats)) {
+        stats[got].tag = VIR_DOMAIN_MEMORY_STAT_ACTUAL_BALLOON;
+        stats[got].val = mem;
+        got++;
+    }
 
-    ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+    if (!balloonpath)
+        goto cleanup;
 
-    if (ret == 0) {
-        /* See if balloon soft-failed */
-        if (qemuMonitorJSONHasError(reply, "DeviceNotActive") ||
-            qemuMonitorJSONHasError(reply, "KVMMissingCap"))
-            goto cleanup;
+    if (!(cmd = qemuMonitorJSONMakeCommand("qom-get",
+                                           "s:path", balloonpath,
+                                           "s:property", "guest-stats",
+                                           NULL)))
+        goto cleanup;
 
-        /* See if any other fatal error occurred */
-        ret = qemuMonitorJSONCheckError(cmd, reply);
+    ret = qemuMonitorJSONCommand(mon, cmd, &reply);
 
-        /* Success */
-        if (ret == 0) {
-            virJSONValuePtr data;
-            unsigned long long mem;
+    if (ret == 0)
+        ret = qemuMonitorJSONCheckError(cmd, reply);
 
-            if (!(data = virJSONValueObjectGet(reply, "return"))) {
-                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                               _("info balloon reply was missing return data"));
-                ret = -1;
-                goto cleanup;
-            }
+    if (ret < 0)
+        goto cleanup;
 
-            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++;
-            }
+    if (!(data = virJSONValueObjectGet(reply, "return"))) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("qom-get reply was missing return data"));
+        goto cleanup;
+    }
 
-            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++;
-            }
-        }
+    if (!(statsdata = virJSONValueObjectGet(data, "stats"))) {
+        VIR_DEBUG("data does not include 'stats'");
+        goto cleanup;
     }
 
-    if (got > 0)
-        ret = got;
+    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);
+
 
 cleanup:
     virJSONValueFree(cmd);
     virJSONValueFree(reply);
+
+    if (got > 0)
+        ret = got;
+
     return ret;
 }
+#undef GET_BALLOON_STATS
 
 
 /*
index 8daa7173e74f4abf6aee22511f5f79badbea90d1..e94abf298d75cb04d72d1660f0039771ee00eb28 100644 (file)
@@ -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,