From: "Michael R. Hines" <mrhines@xxxxxxxxxx> RDMA migration uses the 'setup' state in QEMU to optionally lock all memory before the migration starts. The total time spent in this state is exposed as VIR_DOMAIN_JOB_SETUP_TIME. Additionally, QEMU also exports migration throughput (mbps) for both memory and disk, so let's add them too: VIR_DOMAIN_JOB_MEMORY_BPS, VIR_DOMAIN_JOB_DISK_BPS. Signed-off-by: Michael R. Hines <mrhines@xxxxxxxxxx> Signed-off-by: Jiri Denemark <jdenemar@xxxxxxxxxx> --- Notes: Version 3: - changed MBPS to BPS - added support for both memory and disk BPS - changed BPS to ULLONG - added code to transfer the new statistics to the destination daemon when migration completes - added the new parameters to virsh include/libvirt/libvirt.h.in | 25 +++++++++++++++++++++++++ src/qemu/qemu_domain.c | 18 ++++++++++++++++++ src/qemu/qemu_migration.c | 17 +++++++++++++++++ src/qemu/qemu_monitor.h | 9 +++++++++ src/qemu/qemu_monitor_json.c | 17 +++++++++++++++++ tools/virsh-domain.c | 27 +++++++++++++++++++++++++++ 6 files changed, 113 insertions(+) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index c2f9d26..702f797 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -4388,6 +4388,15 @@ int virDomainAbortJob(virDomainPtr dom); #define VIR_DOMAIN_JOB_DOWNTIME "downtime" /** + * VIR_DOMAIN_JOB_SETUP_TIME: + * + * virDomainGetJobStats field: total time in milliseconds spent preparing + * the migration in the 'setup' phase before the iterations begin, as + * VIR_TYPED_PARAM_ULLONG. + */ +#define VIR_DOMAIN_JOB_SETUP_TIME "setup_time" + +/** * VIR_DOMAIN_JOB_DATA_TOTAL: * * virDomainGetJobStats field: total number of bytes supposed to be @@ -4485,6 +4494,14 @@ int virDomainAbortJob(virDomainPtr dom); #define VIR_DOMAIN_JOB_MEMORY_NORMAL_BYTES "memory_normal_bytes" /** + * VIR_DOMAIN_JOB_MEMORY_BPS: + * + * virDomainGetJobStats field: network throughput used while migrating + * memory in Bytes per second, as VIR_TYPED_PARAM_ULLONG. + */ +#define VIR_DOMAIN_JOB_MEMORY_BPS "memory_bps" + +/** * VIR_DOMAIN_JOB_DISK_TOTAL: * * virDomainGetJobStats field: as VIR_DOMAIN_JOB_DATA_TOTAL but only @@ -4515,6 +4532,14 @@ int virDomainAbortJob(virDomainPtr dom); #define VIR_DOMAIN_JOB_DISK_REMAINING "disk_remaining" /** + * VIR_DOMAIN_JOB_DISK_BPS: + * + * virDomainGetJobStats field: network throughput used while migrating + * disks in Bytes per second, as VIR_TYPED_PARAM_ULLONG. + */ +#define VIR_DOMAIN_JOB_DISK_BPS "disk_bps" + +/** * VIR_DOMAIN_JOB_COMPRESSION_CACHE: * * virDomainGetJobStats field: size of the cache (in bytes) used for diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 863ab09..9b3edd7 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -304,6 +304,12 @@ qemuDomainJobInfoToParams(qemuDomainJobInfoPtr jobInfo, status->downtime) < 0) goto error; + if (status->setup_time_set && + virTypedParamsAddULLong(&par, &npar, &maxpar, + VIR_DOMAIN_JOB_SETUP_TIME, + status->setup_time) < 0) + goto error; + if (virTypedParamsAddULLong(&par, &npar, &maxpar, VIR_DOMAIN_JOB_DATA_TOTAL, status->ram_total + @@ -329,6 +335,12 @@ qemuDomainJobInfoToParams(qemuDomainJobInfoPtr jobInfo, status->ram_remaining) < 0) goto error; + if (status->ram_bps && + virTypedParamsAddULLong(&par, &npar, &maxpar, + VIR_DOMAIN_JOB_MEMORY_BPS, + status->ram_bps) < 0) + goto error; + if (status->ram_duplicate_set) { if (virTypedParamsAddULLong(&par, &npar, &maxpar, VIR_DOMAIN_JOB_MEMORY_CONSTANT, @@ -353,6 +365,12 @@ qemuDomainJobInfoToParams(qemuDomainJobInfoPtr jobInfo, status->disk_remaining) < 0) goto error; + if (status->disk_bps && + virTypedParamsAddULLong(&par, &npar, &maxpar, + VIR_DOMAIN_JOB_DISK_BPS, + status->disk_bps) < 0) + goto error; + if (status->xbzrle_set) { if (virTypedParamsAddULLong(&par, &npar, &maxpar, VIR_DOMAIN_JOB_COMPRESSION_CACHE, diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index ce1a5cd..d738f9b 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -636,6 +636,10 @@ qemuMigrationCookieStatisticsXMLFormat(virBufferPtr buf, virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n", VIR_DOMAIN_JOB_DOWNTIME, status->downtime); + if (status->setup_time_set) + virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n", + VIR_DOMAIN_JOB_SETUP_TIME, + status->setup_time); virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n", VIR_DOMAIN_JOB_MEMORY_TOTAL, @@ -646,6 +650,9 @@ qemuMigrationCookieStatisticsXMLFormat(virBufferPtr buf, virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n", VIR_DOMAIN_JOB_MEMORY_REMAINING, status->ram_remaining); + virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n", + VIR_DOMAIN_JOB_MEMORY_BPS, + status->ram_bps); if (status->ram_duplicate_set) { virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n", @@ -668,6 +675,9 @@ qemuMigrationCookieStatisticsXMLFormat(virBufferPtr buf, virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n", VIR_DOMAIN_JOB_DISK_REMAINING, status->disk_remaining); + virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n", + VIR_DOMAIN_JOB_DISK_BPS, + status->disk_bps); if (status->xbzrle_set) { virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n", @@ -904,6 +914,9 @@ qemuMigrationCookieStatisticsXMLParse(xmlXPathContextPtr ctxt) if (virXPathULongLong("string(./" VIR_DOMAIN_JOB_DOWNTIME "[1])", ctxt, &status->downtime) == 0) status->downtime_set = true; + if (virXPathULongLong("string(./" VIR_DOMAIN_JOB_SETUP_TIME "[1])", + ctxt, &status->setup_time) == 0) + status->setup_time_set = true; virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_TOTAL "[1])", ctxt, &status->ram_total); @@ -911,6 +924,8 @@ qemuMigrationCookieStatisticsXMLParse(xmlXPathContextPtr ctxt) ctxt, &status->ram_transferred); virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_REMAINING "[1])", ctxt, &status->ram_remaining); + virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_BPS "[1])", + ctxt, &status->ram_bps); if (virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_CONSTANT "[1])", ctxt, &status->ram_duplicate) == 0) @@ -926,6 +941,8 @@ qemuMigrationCookieStatisticsXMLParse(xmlXPathContextPtr ctxt) ctxt, &status->disk_transferred); virXPathULongLong("string(./" VIR_DOMAIN_JOB_DISK_REMAINING "[1])", ctxt, &status->disk_remaining); + virXPathULongLong("string(./" VIR_DOMAIN_JOB_DISK_BPS "[1])", + ctxt, &status->disk_bps); if (virXPathULongLong("string(./" VIR_DOMAIN_JOB_COMPRESSION_CACHE "[1])", ctxt, &status->xbzrle_cache_size) == 0) diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 61a14d4..5fb83ff 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -423,10 +423,18 @@ struct _qemuMonitorMigrationStatus { /* total or expected depending on status */ bool downtime_set; unsigned long long downtime; + /* + * Duration of the QEMU 'setup' state. + * for RDMA, this may be on the order of several seconds + * if pinning support is requested before the migration begins. + */ + bool setup_time_set; + unsigned long long setup_time; unsigned long long ram_transferred; unsigned long long ram_remaining; unsigned long long ram_total; + unsigned long long ram_bps; bool ram_duplicate_set; unsigned long long ram_duplicate; unsigned long long ram_normal; @@ -435,6 +443,7 @@ struct _qemuMonitorMigrationStatus { unsigned long long disk_transferred; unsigned long long disk_remaining; unsigned long long disk_total; + unsigned long long disk_bps; bool xbzrle_set; unsigned long long xbzrle_cache_size; diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 1e14a95..ce3b2cd 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -2469,6 +2469,7 @@ qemuMonitorJSONGetMigrationStatusReply(virJSONValuePtr reply, virJSONValuePtr ret; const char *statusstr; int rc; + double mbps; if (!(ret = virJSONValueObjectGet(reply, "return"))) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", @@ -2501,6 +2502,10 @@ qemuMonitorJSONGetMigrationStatusReply(virJSONValuePtr reply, if (rc == 0) status->downtime_set = true; + if (virJSONValueObjectGetNumberUlong(ret, "setup-time", + &status->setup_time) == 0) + status->setup_time_set = true; + if (status->status == QEMU_MONITOR_MIGRATION_STATUS_ACTIVE || status->status == QEMU_MONITOR_MIGRATION_STATUS_COMPLETED) { virJSONValuePtr ram = virJSONValueObjectGet(ret, "ram"); @@ -2532,6 +2537,12 @@ qemuMonitorJSONGetMigrationStatusReply(virJSONValuePtr reply, return -1; } + if (virJSONValueObjectGetNumberDouble(ram, "mbps", &mbps) == 0 && + mbps > 0) { + /* mpbs from QEMU reports Mbits/s (M as in 10^6 not Mi as 2^20) */ + status->ram_bps = mbps * (1000 * 1000 / 8); + } + if (virJSONValueObjectGetNumberUlong(ram, "duplicate", &status->ram_duplicate) == 0) status->ram_duplicate_set = true; @@ -2568,6 +2579,12 @@ qemuMonitorJSONGetMigrationStatusReply(virJSONValuePtr reply, "data was missing")); return -1; } + + if (virJSONValueObjectGetNumberDouble(disk, "mbps", &mbps) == 0 && + mbps > 0) { + /* mpbs from QEMU reports Mbits/s (M as in 10^6 not Mi as 2^20) */ + status->disk_bps = mbps * (1000 * 1000 / 8); + } } virJSONValuePtr comp = virJSONValueObjectGet(ret, "xbzrle-cache"); diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 435d045..105b99e 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -5518,6 +5518,16 @@ cmdDomjobinfo(vshControl *ctl, const vshCmd *cmd) vshPrint(ctl, "%-17s %-.3lf %s\n", _("Memory remaining:"), val, unit); val = vshPrettyCapacity(info.memTotal, &unit); vshPrint(ctl, "%-17s %-.3lf %s\n", _("Memory total:"), val, unit); + + if ((rc = virTypedParamsGetULLong(params, nparams, + VIR_DOMAIN_JOB_MEMORY_BPS, + &value)) < 0) { + goto save_error; + } else if (rc && value) { + val = vshPrettyCapacity(value, &unit); + vshPrint(ctl, "%-17s %-.3lf %s/s\n", + _("Memory bandwidth:"), val, unit); + } } if (info.fileTotal || info.fileRemaining || info.fileProcessed) { @@ -5527,6 +5537,16 @@ cmdDomjobinfo(vshControl *ctl, const vshCmd *cmd) vshPrint(ctl, "%-17s %-.3lf %s\n", _("File remaining:"), val, unit); val = vshPrettyCapacity(info.fileTotal, &unit); vshPrint(ctl, "%-17s %-.3lf %s\n", _("File total:"), val, unit); + + if ((rc = virTypedParamsGetULLong(params, nparams, + VIR_DOMAIN_JOB_DISK_BPS, + &value)) < 0) { + goto save_error; + } else if (rc && value) { + val = vshPrettyCapacity(value, &unit); + vshPrint(ctl, "%-17s %-.3lf %s/s\n", + _("File bandwidth:"), val, unit); + } } if ((rc = virTypedParamsGetULLong(params, nparams, @@ -5567,6 +5587,13 @@ cmdDomjobinfo(vshControl *ctl, const vshCmd *cmd) } if ((rc = virTypedParamsGetULLong(params, nparams, + VIR_DOMAIN_JOB_SETUP_TIME, + &value)) < 0) + goto save_error; + else if (rc) + vshPrint(ctl, "%-17s %-12llu ms\n", _("Setup time:"), value); + + if ((rc = virTypedParamsGetULLong(params, nparams, VIR_DOMAIN_JOB_COMPRESSION_CACHE, &value)) < 0) { goto save_error; -- 2.1.0 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list