On Tue, Jul 02, 2013 at 09:39:24AM -0400, John Ferlan wrote:
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.h | 4 +++
src/qemu/qemu_monitor_json.c | 76 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 80 insertions(+)
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index b822b97..4199160 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -703,6 +703,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
} qemuMonitorObjectPropertyType;
@@ -711,6 +712,8 @@ typedef struct _qemuMonitorObjectProperty qemuMonitorObjectProperty;
typedef qemuMonitorObjectProperty *qemuMonitorObjectPropertyPtr;
struct _qemuMonitorObjectProperty {
int type; /* qemuMonitorObjectPropertyType */
+ int curelems; /* Current number elements in **ptr array */
+ int maxelems; /* Maximum number elements allowed in any **ptr array */
union {
bool b;
int i;
@@ -719,6 +722,7 @@ struct _qemuMonitorObjectProperty {
unsigned long long ul;
double d;
char *str;
+ void **ptr;
Hmm, not sure I really like the look of this opaque pointer.
} val;
};
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index c599626..49001a8 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -4627,6 +4627,78 @@ 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) && \
+ (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++; \
+ } \
+ } \
+ }
+
+static int
+qemuMonitorJSONGetBalloonStats(virJSONValuePtr data,
+ qemuMonitorObjectPropertyPtr prop)
+{
+ int ret = -1;
+ unsigned long long mem;
+ virJSONValuePtr statsdata;
+ virDomainMemoryStatPtr stat = (virDomainMemoryStatPtr)prop->val.ptr;
+
+ VIR_DEBUG("Address of found stat = %p", stat);
+
+ if (!(statsdata = virJSONValueObjectGet(data, "stats"))) {
+ VIR_DEBUG("data does not include 'stats'");
+ goto cleanup;
+ }
+
+ 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);
+
+ ret = 0;
+
+cleanup:
+ virJSONValueFree(statsdata);
+ return ret;
+}
You'll want an '#undef GET_BALLOON_STATS' call.
+
int qemuMonitorJSONGetObjectProperty(qemuMonitorPtr mon,
const char *path,
const char *property,
@@ -4689,6 +4761,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,
@@ -4752,6 +4827,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,
We already have a method qemuMonitor{JSON}GetMemoryStats which was using
the legacy 'query-balloon' interface that QEMU has removed now. IMHO we
should just update that existing API to fetch the data using the new
QOM based monitor commands. Then existing code using that API in the
QEMU driver will "just work".
Daniel
--
|:
http://berrange.com -o-
http://www.flickr.com/photos/dberrange/ :|
|:
http://libvirt.org -o-
http://virt-manager.org :|
|:
http://autobuild.org -o-
http://search.cpan.org/~danberr/ :|
|:
http://entangle-photo.org -o-
http://live.gnome.org/gtk-vnc :|