[libvirt] [PATCH 4/6] qemu: Transfer migration statistics to destination

John Ferlan jferlan at redhat.com
Fri Sep 5 18:47:09 UTC 2014



On 09/01/2014 11:05 AM, Jiri Denemark wrote:
> 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 <jdenemar at redhat.com>
> ---
>  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 208a21f..f1b3d50 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, "<statistics>\n");
> +    virBufferAdjustIndent(buf, 2);
> +
> +    virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
> +                      VIR_DOMAIN_JOB_TIME_ELAPSED,
> +                      jobInfo->timeElapsed);
> +    virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
> +                      VIR_DOMAIN_JOB_TIME_REMAINING,
> +                      jobInfo->timeRemaining);

qemuDomainJobInfoToParams will use jobInfo->type ==
VIR_DOMAIN_JOB_BOUNDED when printing the above - dies this need to as well?

I would suspect this would be zero anyway, right? Since the job is done.

> +    if (status->downtime_set)
> +        virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
> +                          VIR_DOMAIN_JOB_DOWNTIME,
> +                          status->downtime);

What about the VIR_DOMAIN_JOB_DATA_* values? I know they are calculable,
but since they're

> +
> +    virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
> +                      VIR_DOMAIN_JOB_MEMORY_TOTAL,
> +                      status->ram_total);
> +    virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
> +                      VIR_DOMAIN_JOB_MEMORY_PROCESSED,
> +                      status->ram_transferred);
> +    virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
> +                      VIR_DOMAIN_JOB_MEMORY_REMAINING,
> +                      status->ram_remaining);
> +
> +    if (status->ram_duplicate_set) {
> +        virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
> +                          VIR_DOMAIN_JOB_MEMORY_CONSTANT,
> +                          status->ram_duplicate);
> +        virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
> +                          VIR_DOMAIN_JOB_MEMORY_NORMAL,
> +                          status->ram_normal);
> +        virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
> +                          VIR_DOMAIN_JOB_MEMORY_NORMAL_BYTES,
> +                          status->ram_normal_bytes);
> +    }
> +
> +    virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
> +                      VIR_DOMAIN_JOB_DISK_TOTAL,
> +                      status->disk_total);
> +    virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
> +                      VIR_DOMAIN_JOB_DISK_PROCESSED,
> +                      status->disk_transferred);
> +    virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
> +                      VIR_DOMAIN_JOB_DISK_REMAINING,
> +                      status->disk_remaining);
> +
> +    if (status->xbzrle_set) {
> +        virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
> +                          VIR_DOMAIN_JOB_COMPRESSION_CACHE,
> +                          status->xbzrle_cache_size);
> +        virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
> +                          VIR_DOMAIN_JOB_COMPRESSION_BYTES,
> +                          status->xbzrle_bytes);
> +        virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
> +                          VIR_DOMAIN_JOB_COMPRESSION_PAGES,
> +                          status->xbzrle_pages);
> +        virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
> +                          VIR_DOMAIN_JOB_COMPRESSION_CACHE_MISSES,
> +                          status->xbzrle_cache_miss);
> +        virBufferAsprintf(buf, "<%1$s>%2$llu</%1$s>\n",
> +                          VIR_DOMAIN_JOB_COMPRESSION_OVERFLOW,
> +                          status->xbzrle_overflow);
> +    }
> +
> +    virBufferAdjustIndent(buf, -2);
> +    virBufferAddLit(buf, "</statistics>\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, "</qemu-migration>\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;
> +

In the not that it matters department, but some flags checks have

"(flags & FLAG)" while others go with just "flags & FLAG" - doesn't
matter to me, but it's not consistent.

>      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);

This seems out of place - is it because of the impending copy
mig->jobInfo copy?  What if that data wasn't there?  We just wipe out
whatever was possibly there.

ACK - seems OK to me. Just curious about the above.

John

>  
> -    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,
> 




More information about the libvir-list mailing list