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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list