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