[libvirt] [PATCH v4 0/3] qemu: expand domain memory statistics

From: Derbyshev Dmitry <dderbyshev@virtuozzo.com> QEMU reports timestamp and available along with other memory statistics. This information was not saved into domain statistics. Also, to collect all balloon statistics for all guests it was necessary to make several libvirt requests (one per VE). Last patch allows doing this via qemuConnectGetAllDomainStats in one request. Changes since v1: * Enum numeration fixed * Macro getting "usage" field fixed Changes since v2: * previous patches were on wrong branch * qemu's stat name was "stat-available-memory" Changes since v3: * 3rd patch added Derbyshev Dmitry (3): qemu: expand domain memory statistics with 'usable' qemu: expand domain memory statistics with 'last-update' timestamp qemu: return balloon statistics alongside all domain stats include/libvirt/libvirt-domain.h | 11 +++++- src/libvirt-domain.c | 5 +++ src/qemu/qemu_driver.c | 84 +++++++++++++++++++++++++++++++--------- src/qemu/qemu_monitor_json.c | 22 ++++++----- tools/virsh-domain-monitor.c | 4 ++ 5 files changed, 98 insertions(+), 28 deletions(-) -- 1.9.5.msysgit.0

From: Derbyshev Dmitry <dderbyshev@virtuozzo.com> 'memtotal' in virtio drivers and qemu corresponds to 'available' in libvirt. Because of that, 'stat-available-memory' is renamed into 'usable'. Balloon statistics are not reported in hrf, so no modifications are made in qemu_monitor_text.c. Signed-off-by: Derbyshev Dmitry <dderbyshev@virtuozzo.com> --- include/libvirt/libvirt-domain.h | 8 +++++++- src/libvirt-domain.c | 3 +++ src/qemu/qemu_monitor_json.c | 2 ++ tools/virsh-domain-monitor.c | 2 ++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index cba4fa5..1554198 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -604,10 +604,16 @@ typedef enum { VIR_DOMAIN_MEMORY_STAT_RSS = 7, /* + * How big the balloon can be inflated without pushing the guest system + * to swap, corresponds to 'Available' in /proc/meminfo + */ + VIR_DOMAIN_MEMORY_STAT_USABLE = 8, + + /* * The number of statistics supported by this version of the interface. * To add new statistics, add them to the enum and increase this value. */ - VIR_DOMAIN_MEMORY_STAT_NR = 8, + VIR_DOMAIN_MEMORY_STAT_NR = 9, # ifdef VIR_ENUM_SENTINELS VIR_DOMAIN_MEMORY_STAT_LAST = VIR_DOMAIN_MEMORY_STAT_NR diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c index 73ae369..fabd4a6 100644 --- a/src/libvirt-domain.c +++ b/src/libvirt-domain.c @@ -5986,6 +5986,9 @@ virDomainGetInterfaceParameters(virDomainPtr domain, * The amount of memory which is not being used for any purpose (in kb). * VIR_DOMAIN_MEMORY_STAT_AVAILABLE: * The total amount of memory available to the domain's OS (in kb). + * VIR_DOMAIN_MEMORY_STAT_USABLE: + * How big the balloon can be inflated without pushing the guest system + * to swap, corresponds to 'Available' in /proc/meminfo * VIR_DOMAIN_MEMORY_STAT_ACTUAL_BALLOON: * Current balloon value (in kb). * diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 585b882..f0c001b 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -1719,6 +1719,8 @@ int qemuMonitorJSONGetMemoryStats(qemuMonitorPtr mon, VIR_DOMAIN_MEMORY_STAT_UNUSED, 1024); GET_BALLOON_STATS("stat-total-memory", VIR_DOMAIN_MEMORY_STAT_AVAILABLE, 1024); + GET_BALLOON_STATS("stat-available-memory", + VIR_DOMAIN_MEMORY_STAT_USABLE, 1024); ret = got; cleanup: virJSONValueFree(cmd); diff --git a/tools/virsh-domain-monitor.c b/tools/virsh-domain-monitor.c index 0a93949..1921ff5 100644 --- a/tools/virsh-domain-monitor.c +++ b/tools/virsh-domain-monitor.c @@ -369,6 +369,8 @@ cmdDomMemStat(vshControl *ctl, const vshCmd *cmd) vshPrint(ctl, "unused %llu\n", stats[i].val); if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_AVAILABLE) vshPrint(ctl, "available %llu\n", stats[i].val); + if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_USABLE) + vshPrint(ctl, "usable %llu\n", stats[i].val); if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_ACTUAL_BALLOON) vshPrint(ctl, "actual %llu\n", stats[i].val); if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_RSS) -- 1.9.5.msysgit.0

From: Derbyshev Dmitry <dderbyshev@virtuozzo.com> QEMU reports timestamp along with other memory statistics, but this information is not saved into domain statistics. It could be useful to determine if the data reported is fresh or not. Balloon statistics are not reported in hrf, so no modifications are made in qemu_monitor_text.c. Signed-off-by: Derbyshev Dmitry <dderbyshev@virtuozzo.com> --- include/libvirt/libvirt-domain.h | 5 ++++- src/libvirt-domain.c | 2 ++ src/qemu/qemu_monitor_json.c | 22 ++++++++++++---------- tools/virsh-domain-monitor.c | 2 ++ 4 files changed, 20 insertions(+), 11 deletions(-) diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 1554198..f953897 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -609,11 +609,14 @@ typedef enum { */ VIR_DOMAIN_MEMORY_STAT_USABLE = 8, + /* Timestamp of the last update of statistics */ + VIR_DOMAIN_MEMORY_STAT_LAST_UPDATE = 9, + /* * The number of statistics supported by this version of the interface. * To add new statistics, add them to the enum and increase this value. */ - VIR_DOMAIN_MEMORY_STAT_NR = 9, + VIR_DOMAIN_MEMORY_STAT_NR = 10, # ifdef VIR_ENUM_SENTINELS VIR_DOMAIN_MEMORY_STAT_LAST = VIR_DOMAIN_MEMORY_STAT_NR diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c index fabd4a6..29e0c72 100644 --- a/src/libvirt-domain.c +++ b/src/libvirt-domain.c @@ -5991,6 +5991,8 @@ virDomainGetInterfaceParameters(virDomainPtr domain, * to swap, corresponds to 'Available' in /proc/meminfo * VIR_DOMAIN_MEMORY_STAT_ACTUAL_BALLOON: * Current balloon value (in kb). + * VIR_DOMAIN_MEMORY_STAT_LAST_UPDATE + * Timestamp of the last statistic * * Returns: The number of stats provided or -1 in case of failure. */ diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index f0c001b..726ce04 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -1633,10 +1633,10 @@ qemuMonitorJSONGetBalloonInfo(qemuMonitorPtr mon, * 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) && \ +#define GET_BALLOON_STATS(OBJECT, FIELD, TAG, DIVISOR) \ + if (virJSONValueObjectHasKey(OBJECT, FIELD) && \ (got < nr_stats)) { \ - if (virJSONValueObjectGetNumberUlong(statsdata, FIELD, &mem) < 0) { \ + if (virJSONValueObjectGetNumberUlong(OBJECT, FIELD, &mem) < 0) { \ VIR_DEBUG("Failed to get '%s' value", FIELD); \ } else { \ /* Not being collected? No point in providing bad data */ \ @@ -1707,20 +1707,22 @@ int qemuMonitorJSONGetMemoryStats(qemuMonitorPtr mon, goto cleanup; } - GET_BALLOON_STATS("stat-swap-in", + GET_BALLOON_STATS(statsdata, "stat-swap-in", VIR_DOMAIN_MEMORY_STAT_SWAP_IN, 1024); - GET_BALLOON_STATS("stat-swap-out", + GET_BALLOON_STATS(statsdata, "stat-swap-out", VIR_DOMAIN_MEMORY_STAT_SWAP_OUT, 1024); - GET_BALLOON_STATS("stat-major-faults", + GET_BALLOON_STATS(statsdata, "stat-major-faults", VIR_DOMAIN_MEMORY_STAT_MAJOR_FAULT, 1); - GET_BALLOON_STATS("stat-minor-faults", + GET_BALLOON_STATS(statsdata, "stat-minor-faults", VIR_DOMAIN_MEMORY_STAT_MINOR_FAULT, 1); - GET_BALLOON_STATS("stat-free-memory", + GET_BALLOON_STATS(statsdata, "stat-free-memory", VIR_DOMAIN_MEMORY_STAT_UNUSED, 1024); - GET_BALLOON_STATS("stat-total-memory", + GET_BALLOON_STATS(statsdata, "stat-total-memory", VIR_DOMAIN_MEMORY_STAT_AVAILABLE, 1024); - GET_BALLOON_STATS("stat-available-memory", + GET_BALLOON_STATS(statsdata, "stat-available-memory", VIR_DOMAIN_MEMORY_STAT_USABLE, 1024); + GET_BALLOON_STATS(data, "last-update", + VIR_DOMAIN_MEMORY_STAT_LAST_UPDATE, 1); ret = got; cleanup: virJSONValueFree(cmd); diff --git a/tools/virsh-domain-monitor.c b/tools/virsh-domain-monitor.c index 1921ff5..b4ccbf6 100644 --- a/tools/virsh-domain-monitor.c +++ b/tools/virsh-domain-monitor.c @@ -375,6 +375,8 @@ cmdDomMemStat(vshControl *ctl, const vshCmd *cmd) vshPrint(ctl, "actual %llu\n", stats[i].val); if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_RSS) vshPrint(ctl, "rss %llu\n", stats[i].val); + if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_LAST_UPDATE) + vshPrint(ctl, "last_update %llu\n", stats[i].val); } ret = true; -- 1.9.5.msysgit.0

From: Derbyshev Dmitry <dderbyshev@virtuozzo.com> To collect all balloon statistics for all guests it was necessary to make several libvirt requests (one per VE). This patch allows doing this via qemuConnectGetAllDomainStats in one request. Changes: * qemuDomainMemoryStats became a helper function which calls qemuDomainMemoryStatsInternal, which contains all logic. * flags in qemuDomainMemoryStatsInternal may passed from qemuDomainMemoryStats or qemuDomainGetStatsBalloon via different variables * qemuDomainGetStatsBalloon reports memory stats fields by calling qemuDomainMemoryStatsInternal Signed-off-by: Derbyshev Dmitry <dderbyshev@virtuozzo.com> --- src/qemu/qemu_driver.c | 84 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 66 insertions(+), 18 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index fc43bcb..4dbd4ed 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -11120,31 +11120,21 @@ qemuDomainGetInterfaceParameters(virDomainPtr dom, } static int -qemuDomainMemoryStats(virDomainPtr dom, - virDomainMemoryStatPtr stats, - unsigned int nr_stats, - unsigned int flags) +qemuDomainMemoryStatsInternal(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virDomainMemoryStatPtr stats, + unsigned int nr_stats, + unsigned int flags) { - virQEMUDriverPtr driver = dom->conn->privateData; - virDomainObjPtr vm; int ret = -1; long rss; virCheckFlags(0, -1); - if (!(vm = qemuDomObjFromDomain(dom))) - goto cleanup; - - if (virDomainMemoryStatsEnsureACL(dom->conn, vm->def) < 0) - goto cleanup; - - if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0) - goto cleanup; - if (!virDomainObjIsActive(vm)) { virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("domain is not running")); - goto endjob; + goto cleanup; } if (vm->def->memballoon && @@ -11155,7 +11145,7 @@ qemuDomainMemoryStats(virDomainPtr dom, ret = -1; if (ret < 0 || ret >= nr_stats) - goto endjob; + goto cleanup; } else { ret = 0; } @@ -11169,7 +11159,33 @@ qemuDomainMemoryStats(virDomainPtr dom, ret++; } - endjob: + cleanup: + return ret; +} + +static int +qemuDomainMemoryStats(virDomainPtr dom, + virDomainMemoryStatPtr stats, + unsigned int nr_stats, + unsigned int flags) +{ + virQEMUDriverPtr driver = dom->conn->privateData; + virDomainObjPtr vm; + int ret = -1; + + virCheckFlags(0, -1); + + if (!(vm = qemuDomObjFromDomain(dom))) + goto cleanup; + + if (virDomainMemoryStatsEnsureACL(dom->conn, vm->def) < 0) + goto cleanup; + + if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0) + goto cleanup; + + ret = qemuDomainMemoryStatsInternal(driver, vm, stats, nr_stats, flags); + qemuDomainObjEndJob(driver, vm); cleanup: @@ -18650,6 +18666,17 @@ qemuDomainGetStatsCpu(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, return 0; } + +#define STORE_MEM_RECORD(TAG, NAME) { \ + if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_ ##TAG) \ + if (virTypedParamsAddULLong(&record->params, \ + &record->nparams, \ + maxparams, \ + "balloon." NAME, \ + stats[i].val) < 0) \ + return -1; \ +} + static int qemuDomainGetStatsBalloon(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, virDomainObjPtr dom, @@ -18658,7 +18685,10 @@ qemuDomainGetStatsBalloon(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, unsigned int privflags ATTRIBUTE_UNUSED) { qemuDomainObjPrivatePtr priv = dom->privateData; + virDomainMemoryStatStruct stats[VIR_DOMAIN_MEMORY_STAT_NR]; + int nr_stats; unsigned long long cur_balloon = 0; + size_t i; int err = 0; if (!virDomainDefHasMemballoon(dom->def)) { @@ -18683,8 +18713,26 @@ qemuDomainGetStatsBalloon(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, virDomainDefGetMemoryActual(dom->def)) < 0) return -1; + nr_stats = qemuDomainMemoryStatsInternal(driver, dom, stats, + VIR_DOMAIN_MEMORY_STAT_NR, 0); + if (nr_stats < 0) + return 0; + for (i = 0; i < nr_stats; i++) { + STORE_MEM_RECORD(SWAP_IN, "swap_in") + STORE_MEM_RECORD(SWAP_OUT, "swap_out") + STORE_MEM_RECORD(MAJOR_FAULT, "major_fault") + STORE_MEM_RECORD(MINOR_FAULT, "minor_fault") + STORE_MEM_RECORD(UNUSED, "unused") + STORE_MEM_RECORD(AVAILABLE, "available") + STORE_MEM_RECORD(ACTUAL_BALLOON, "actual") + STORE_MEM_RECORD(RSS, "rss") + STORE_MEM_RECORD(LAST_UPDATE, "last-update") + STORE_MEM_RECORD(USABLE, "usable") + } + return 0; } +#undef STORE_MEM_RECORD static int -- 1.9.5.msysgit.0

08.06.2016 16:30, Derbyshev Dmitriy пишет:
From: Derbyshev Dmitry <dderbyshev@virtuozzo.com>
QEMU reports timestamp and available along with other memory statistics. This information was not saved into domain statistics.
Also, to collect all balloon statistics for all guests it was necessary to make several libvirt requests (one per VE). Last patch allows doing this via qemuConnectGetAllDomainStats in one request.
Changes since v1: * Enum numeration fixed * Macro getting "usage" field fixed Changes since v2: * previous patches were on wrong branch * qemu's stat name was "stat-available-memory" Changes since v3: * 3rd patch added
ACK to the series. Looks good to me, but someone else should see also. Maxim

09.06.2016 20:34, Maxim Nestratov пишет:
08.06.2016 16:30, Derbyshev Dmitriy пишет:
From: Derbyshev Dmitry <dderbyshev@virtuozzo.com>
QEMU reports timestamp and available along with other memory statistics. This information was not saved into domain statistics.
Also, to collect all balloon statistics for all guests it was necessary to make several libvirt requests (one per VE). Last patch allows doing this via qemuConnectGetAllDomainStats in one request.
Changes since v1: * Enum numeration fixed * Macro getting "usage" field fixed Changes since v2: * previous patches were on wrong branch * qemu's stat name was "stat-available-memory" Changes since v3: * 3rd patch added
ACK to the series. Looks good to me, but someone else should see also.
Maxim
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Could anyone take a look at this? Thanks, Maxim

08.06.2016 16:30, Derbyshev Dmitriy пишет:
From: Derbyshev Dmitry <dderbyshev@virtuozzo.com>
QEMU reports timestamp and available along with other memory statistics. This information was not saved into domain statistics.
Also, to collect all balloon statistics for all guests it was necessary to make several libvirt requests (one per VE). Last patch allows doing this via qemuConnectGetAllDomainStats in one request.
Changes since v1: * Enum numeration fixed * Macro getting "usage" field fixed Changes since v2: * previous patches were on wrong branch * qemu's stat name was "stat-available-memory" Changes since v3: * 3rd patch added
Derbyshev Dmitry (3): qemu: expand domain memory statistics with 'usable' qemu: expand domain memory statistics with 'last-update' timestamp qemu: return balloon statistics alongside all domain stats
include/libvirt/libvirt-domain.h | 11 +++++- src/libvirt-domain.c | 5 +++ src/qemu/qemu_driver.c | 84 +++++++++++++++++++++++++++++++--------- src/qemu/qemu_monitor_json.c | 22 ++++++----- tools/virsh-domain-monitor.c | 4 ++ 5 files changed, 98 insertions(+), 28 deletions(-)
Please ignore this version of the series as it had a bug causing libvirt to crash on simultaneous qemuMonitorSend call. v5 series is sent. Maxim
participants (2)
-
Derbyshev Dmitriy
-
Maxim Nestratov