diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 724314eed2..b79e6c04a9 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -4392,6 +4392,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: * @@ -4489,6 +4498,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: * @@ -4519,6 +4536,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: * diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 95b71b74ab..5aad7361db 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 ce1a5cdaa1..d738f9b8f6 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\n", VIR_DOMAIN_JOB_DOWNTIME, status->downtime); + if (status->setup_time_set) + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_SETUP_TIME, + status->setup_time); virBufferAsprintf(buf, "<%1$s>%2$llu\n", VIR_DOMAIN_JOB_MEMORY_TOTAL, @@ -646,6 +650,9 @@ qemuMigrationCookieStatisticsXMLFormat(virBufferPtr buf, virBufferAsprintf(buf, "<%1$s>%2$llu\n", VIR_DOMAIN_JOB_MEMORY_REMAINING, status->ram_remaining); + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_MEMORY_BPS, + status->ram_bps); if (status->ram_duplicate_set) { virBufferAsprintf(buf, "<%1$s>%2$llu\n", @@ -668,6 +675,9 @@ qemuMigrationCookieStatisticsXMLFormat(virBufferPtr buf, virBufferAsprintf(buf, "<%1$s>%2$llu\n", VIR_DOMAIN_JOB_DISK_REMAINING, status->disk_remaining); + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_DISK_BPS, + status->disk_bps); if (status->xbzrle_set) { virBufferAsprintf(buf, "<%1$s>%2$llu\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 2a43a3ca39..0a2059ab47 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -443,10 +443,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; @@ -455,6 +463,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 857edf1dd7..39dc8cd3d8 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -2519,6 +2519,7 @@ qemuMonitorJSONGetMigrationStatusReply(virJSONValuePtr reply, virJSONValuePtr ret; const char *statusstr; int rc; + double mbps; if (!(ret = virJSONValueObjectGet(reply, "return"))) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", @@ -2551,6 +2552,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"); @@ -2582,6 +2587,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; @@ -2618,6 +2629,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 435d04554d..105b99efd3 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, @@ -5566,6 +5586,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) {