From b03557531795877c47dd9b0aaa6f4fb0c154c87a Mon Sep 17 00:00:00 2001 Message-Id: From: Jiri Denemark Date: Thu, 28 Aug 2014 14:06:10 +0200 Subject: [PATCH] qemu: Transfer migration statistics to destination When migrating a transient domain or with VIR_MIGRATE_UNDEFINE_SOURCE flag, the domain may disappear from source host. And so will migration statistics associated with the domain. We need to transfer the statistics at the end of a migration so that they can be queried at the destination host. Signed-off-by: Jiri Denemark (cherry picked from commit 5d6fb96338bb8fcb687e22afda2cd7db16b01165) https://bugzilla.redhat.com/show_bug.cgi?id=1063724 Signed-off-by: Jiri Denemark --- src/qemu/qemu_migration.c | 190 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 187 insertions(+), 3 deletions(-) diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index ba3ca66..9b1e94b 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -80,6 +80,7 @@ enum qemuMigrationCookieFlags { QEMU_MIGRATION_COOKIE_FLAG_PERSISTENT, QEMU_MIGRATION_COOKIE_FLAG_NETWORK, QEMU_MIGRATION_COOKIE_FLAG_NBD, + QEMU_MIGRATION_COOKIE_FLAG_STATS, QEMU_MIGRATION_COOKIE_FLAG_LAST }; @@ -91,7 +92,8 @@ VIR_ENUM_IMPL(qemuMigrationCookieFlag, "lockstate", "persistent", "network", - "nbd"); + "nbd", + "statistics"); enum qemuMigrationCookieFeatures { QEMU_MIGRATION_COOKIE_GRAPHICS = (1 << QEMU_MIGRATION_COOKIE_FLAG_GRAPHICS), @@ -99,6 +101,7 @@ enum qemuMigrationCookieFeatures { QEMU_MIGRATION_COOKIE_PERSISTENT = (1 << QEMU_MIGRATION_COOKIE_FLAG_PERSISTENT), QEMU_MIGRATION_COOKIE_NETWORK = (1 << QEMU_MIGRATION_COOKIE_FLAG_NETWORK), QEMU_MIGRATION_COOKIE_NBD = (1 << QEMU_MIGRATION_COOKIE_FLAG_NBD), + QEMU_MIGRATION_COOKIE_STATS = (1 << QEMU_MIGRATION_COOKIE_FLAG_STATS), }; typedef struct _qemuMigrationCookieGraphics qemuMigrationCookieGraphics; @@ -169,6 +172,9 @@ struct _qemuMigrationCookie { /* If (flags & QEMU_MIGRATION_COOKIE_NBD) */ qemuMigrationCookieNBDPtr nbd; + + /* If (flags & QEMU_MIGRATION_COOKIE_STATS) */ + qemuDomainJobInfoPtr jobInfo; }; static void qemuMigrationCookieGraphicsFree(qemuMigrationCookieGraphicsPtr grap) @@ -533,6 +539,25 @@ qemuMigrationCookieAddNBD(qemuMigrationCookiePtr mig, } +static int +qemuMigrationCookieAddStatistics(qemuMigrationCookiePtr mig, + virDomainObjPtr vm) +{ + qemuDomainObjPrivatePtr priv = vm->privateData; + + if (!priv->job.completed) + return 0; + + if (!mig->jobInfo && VIR_ALLOC(mig->jobInfo) < 0) + return -1; + + *mig->jobInfo = *priv->job.completed; + mig->flags |= QEMU_MIGRATION_COOKIE_STATS; + + return 0; +} + + static void qemuMigrationCookieGraphicsXMLFormat(virBufferPtr buf, qemuMigrationCookieGraphicsPtr grap) { @@ -589,6 +614,81 @@ qemuMigrationCookieNetworkXMLFormat(virBufferPtr buf, } +static void +qemuMigrationCookieStatisticsXMLFormat(virBufferPtr buf, + qemuDomainJobInfoPtr jobInfo) +{ + qemuMonitorMigrationStatus *status = &jobInfo->status; + + virBufferAddLit(buf, "\n"); + virBufferAdjustIndent(buf, 2); + + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_TIME_ELAPSED, + jobInfo->timeElapsed); + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_TIME_REMAINING, + jobInfo->timeRemaining); + if (status->downtime_set) + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_DOWNTIME, + status->downtime); + + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_MEMORY_TOTAL, + status->ram_total); + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_MEMORY_PROCESSED, + status->ram_transferred); + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_MEMORY_REMAINING, + status->ram_remaining); + + if (status->ram_duplicate_set) { + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_MEMORY_CONSTANT, + status->ram_duplicate); + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_MEMORY_NORMAL, + status->ram_normal); + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_MEMORY_NORMAL_BYTES, + status->ram_normal_bytes); + } + + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_DISK_TOTAL, + status->disk_total); + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_DISK_PROCESSED, + status->disk_transferred); + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_DISK_REMAINING, + status->disk_remaining); + + if (status->xbzrle_set) { + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_COMPRESSION_CACHE, + status->xbzrle_cache_size); + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_COMPRESSION_BYTES, + status->xbzrle_bytes); + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_COMPRESSION_PAGES, + status->xbzrle_pages); + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_COMPRESSION_CACHE_MISSES, + status->xbzrle_cache_miss); + virBufferAsprintf(buf, "<%1$s>%2$llu\n", + VIR_DOMAIN_JOB_COMPRESSION_OVERFLOW, + status->xbzrle_overflow); + } + + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "\n"); +} + + static int qemuMigrationCookieXMLFormat(virQEMUDriverPtr driver, virBufferPtr buf, @@ -650,6 +750,9 @@ qemuMigrationCookieXMLFormat(virQEMUDriverPtr driver, virBufferAddLit(buf, "/>\n"); } + if (mig->flags & QEMU_MIGRATION_COOKIE_STATS && mig->jobInfo) + qemuMigrationCookieStatisticsXMLFormat(buf, mig->jobInfo); + virBufferAdjustIndent(buf, -2); virBufferAddLit(buf, "\n"); return 0; @@ -772,6 +875,70 @@ qemuMigrationCookieNetworkXMLParse(xmlXPathContextPtr ctxt) } +static qemuDomainJobInfoPtr +qemuMigrationCookieStatisticsXMLParse(xmlXPathContextPtr ctxt) +{ + qemuDomainJobInfoPtr jobInfo = NULL; + qemuMonitorMigrationStatus *status; + xmlNodePtr save_ctxt = ctxt->node; + + if (!(ctxt->node = virXPathNode("./statistics", ctxt))) + goto cleanup; + + if (VIR_ALLOC(jobInfo) < 0) + goto cleanup; + + status = &jobInfo->status; + jobInfo->type = VIR_DOMAIN_JOB_COMPLETED; + + virXPathULongLong("string(./" VIR_DOMAIN_JOB_TIME_ELAPSED "[1])", + ctxt, &jobInfo->timeElapsed); + virXPathULongLong("string(./" VIR_DOMAIN_JOB_TIME_REMAINING "[1])", + ctxt, &jobInfo->timeRemaining); + if (virXPathULongLong("string(./" VIR_DOMAIN_JOB_DOWNTIME "[1])", + ctxt, &status->downtime) == 0) + status->downtime_set = true; + + virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_TOTAL "[1])", + ctxt, &status->ram_total); + virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_PROCESSED "[1])", + ctxt, &status->ram_transferred); + virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_REMAINING "[1])", + ctxt, &status->ram_remaining); + + if (virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_CONSTANT "[1])", + ctxt, &status->ram_duplicate) == 0) + status->ram_duplicate_set = true; + virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_NORMAL "[1])", + ctxt, &status->ram_normal); + virXPathULongLong("string(./" VIR_DOMAIN_JOB_MEMORY_NORMAL_BYTES "[1])", + ctxt, &status->ram_normal_bytes); + + virXPathULongLong("string(./" VIR_DOMAIN_JOB_DISK_TOTAL "[1])", + ctxt, &status->disk_total); + virXPathULongLong("string(./" VIR_DOMAIN_JOB_DISK_PROCESSED "[1])", + ctxt, &status->disk_transferred); + virXPathULongLong("string(./" VIR_DOMAIN_JOB_DISK_REMAINING "[1])", + ctxt, &status->disk_remaining); + + if (virXPathULongLong("string(./" VIR_DOMAIN_JOB_COMPRESSION_CACHE "[1])", + ctxt, &status->xbzrle_cache_size) == 0) + status->xbzrle_set = true; + virXPathULongLong("string(./" VIR_DOMAIN_JOB_COMPRESSION_BYTES "[1])", + ctxt, &status->xbzrle_bytes); + virXPathULongLong("string(./" VIR_DOMAIN_JOB_COMPRESSION_PAGES "[1])", + ctxt, &status->xbzrle_pages); + virXPathULongLong("string(./" VIR_DOMAIN_JOB_COMPRESSION_CACHE_MISSES "[1])", + ctxt, &status->xbzrle_cache_miss); + virXPathULongLong("string(./" VIR_DOMAIN_JOB_COMPRESSION_OVERFLOW "[1])", + ctxt, &status->xbzrle_overflow); + + cleanup: + ctxt->node = save_ctxt; + return jobInfo; +} + + static int qemuMigrationCookieXMLParse(qemuMigrationCookiePtr mig, virQEMUDriverPtr driver, @@ -947,6 +1114,11 @@ qemuMigrationCookieXMLParse(qemuMigrationCookiePtr mig, VIR_FREE(port); } + if (flags & QEMU_MIGRATION_COOKIE_STATS && + virXPathBoolean("boolean(./statistics)", ctxt) && + (!(mig->jobInfo = qemuMigrationCookieStatisticsXMLParse(ctxt)))) + goto error; + virObjectUnref(caps); return 0; @@ -1017,6 +1189,10 @@ qemuMigrationBakeCookie(qemuMigrationCookiePtr mig, qemuMigrationCookieAddNBD(mig, driver, dom) < 0) return -1; + if (flags & QEMU_MIGRATION_COOKIE_STATS && + qemuMigrationCookieAddStatistics(mig, dom) < 0) + return -1; + if (!(*cookieout = qemuMigrationCookieXMLFormatStr(driver, mig))) return -1; @@ -3424,7 +3600,8 @@ qemuMigrationRun(virQEMUDriverPtr driver, if (priv->job.completed) qemuDomainJobInfoUpdateTime(priv->job.completed); - cookieFlags |= QEMU_MIGRATION_COOKIE_NETWORK; + cookieFlags |= QEMU_MIGRATION_COOKIE_NETWORK | + QEMU_MIGRATION_COOKIE_STATS; if (flags & VIR_MIGRATE_PERSIST_DEST) cookieFlags |= QEMU_MIGRATION_COOKIE_PERSISTENT; if (ret == 0 && @@ -4508,8 +4685,10 @@ qemuMigrationFinish(virQEMUDriverPtr driver, : QEMU_MIGRATION_PHASE_FINISH2); qemuDomainCleanupRemove(vm, qemuMigrationPrepareCleanup); + VIR_FREE(priv->job.completed); - cookie_flags = QEMU_MIGRATION_COOKIE_NETWORK; + cookie_flags = QEMU_MIGRATION_COOKIE_NETWORK | + QEMU_MIGRATION_COOKIE_STATS; if (flags & VIR_MIGRATE_PERSIST_DEST) cookie_flags |= QEMU_MIGRATION_COOKIE_PERSISTENT; @@ -4527,6 +4706,11 @@ qemuMigrationFinish(virQEMUDriverPtr driver, goto endjob; } + if (mig->jobInfo) { + priv->job.completed = mig->jobInfo; + mig->jobInfo = NULL; + } + if (!(flags & VIR_MIGRATE_OFFLINE)) { if (qemuMigrationVPAssociatePortProfiles(vm->def) < 0) { qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED, -- 2.1.0