qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: mrhines@linux.vnet.ibm.com
To: qemu-devel@nongnu.org
Cc: hinesmr@cn.ibm.com, "Michael R. Hines" <mrhines@us.ibm.com>,
	quintela@redhat.com
Subject: [Qemu-devel] [RFC PATCH v1 2/3] provenance: serialize MigrationInfo across the wire
Date: Tue, 18 Feb 2014 13:53:21 +0800	[thread overview]
Message-ID: <1392702802-11592-3-git-send-email-mrhines@linux.vnet.ibm.com> (raw)
In-Reply-To: <1392702802-11592-1-git-send-email-mrhines@linux.vnet.ibm.com>

From: "Michael R. Hines" <mrhines@us.ibm.com>

At the end of the migration, we use the existing QMP json manipulation
functions and the query-migrate QMP function to serialize the MigrationInfo
structure that was populated in the 'COMPLETED' state of the migration.

This code does not need to know anything about the actual contents of the
MigrationInfo structure, as the QMP code has taken care of all of the hard
work of serializing and visiting all of the individual fields of the structure.
Once we have a QObject, we convert that to JSON and send it across the
connection at the end of the migration.

The only exception to the serialization is the 'downtime' field. Previously
this was calculated inside the migration_thread, but because want to ensure
that this field is serialized as well, we need to calculate it just a little
bit earlier.

Once the json is received on the other side, we perform the reverse of
all the previous steps and convert the json string back into a MigrationInfo
structure just as it was before.

The information in this structure will only last as long as the next migration,
so if another migration occurs, it is the responsibility of the management
software to extract the information before the next migration begins or else
the information will be lost.

Signed-off-by: Michael R. Hines <mrhines@us.ibm.com>
---
 migration.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 121 insertions(+), 5 deletions(-)

diff --git a/migration.c b/migration.c
index 25add6f..8acabf0 100644
--- a/migration.c
+++ b/migration.c
@@ -24,6 +24,10 @@
 #include "migration/block.h"
 #include "qemu/thread.h"
 #include "qmp-commands.h"
+#include "qapi/qmp/qobject.h"
+#include "qapi/qmp/qstring.h"
+#include "qapi/qmp/qint.h"
+#include "qapi/qmp/qjson.h"
 #include "trace.h"
 
 //#define DEBUG_MIGRATION
@@ -183,6 +187,115 @@ static void get_xbzrle_cache_stats(MigrationInfo *info)
     }
 }
 
+/*
+ * 'last_info' is not a device, per-se, but the existing device state
+ * state transfer mechanism is very easy to use for this purpose, as
+ * we're only (currently) interested in communicating this information
+ * in-band after the last migration round has completed (as opposed to
+ * out-of-band, which would require more intelligence in the management
+ * software, for example).
+ */
+void migrate_info_save(QEMUFile *f, void *opaque)
+{
+    MigrationState *s = migrate_get_current();
+    QObject *info;
+    QString * qjson;
+    QInt *downtime;
+    uint32_t len;
+    const char * json;
+    int64_t end_time;
+
+    /*
+     * Use the existing QMP command to get the statistics.
+     */
+    qmp_marshal_input_query_migrate(NULL, NULL, &info);
+
+    /*
+     * Update the structure with the final downtime of the migration.
+     */
+    end_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
+    s->total_time = end_time - s->total_time;
+    s->downtime = end_time - s->start_time;
+    downtime = qint_from_int(s->downtime);
+
+    qdict_put_obj(qobject_to_qdict(info), "downtime", QOBJECT(downtime));
+
+    /*
+     * Serialize into raw JSON and send to other side only
+     * after the last migration round has completed.
+     */
+    qjson = qobject_to_json(info);
+    json = qstring_get_str(qjson);
+
+    len = strlen(json);
+    qemu_put_be32(f, len);
+    qemu_put_buffer(f, (uint8_t *)json, len);
+
+    qemu_fflush(f);
+
+    qobject_decref(QOBJECT(qjson));
+    qobject_decref(info);
+    qobject_decref(QOBJECT(downtime));
+}
+
+/*
+ * The source has nearly completed the migration and has sent
+ * out a JSON description of the migration performance statistics.
+ * Load it and use the QMP 'migrate-set-last-info' command to automatically
+ * convert it into a usable structure.
+ */
+int migrate_info_load(QEMUFile *f, void *opaque, int version_id)
+{
+    uint32_t len = qemu_get_be32(f);
+    char * json = g_malloc0(len + 1);
+    QDict *info = qdict_new();
+
+    qemu_get_buffer(f, (uint8_t *)json, len);
+
+    /*
+     * Construct a { 'info' : MigrationInfo } structure
+     * out of the resulting JSON for QMP to parse the input.
+     */
+    qdict_put_obj(info, "info", qobject_from_json(json));
+    DPRINTF("migrate_info_load: %s\n", json);
+    g_free(json);
+    qmp_marshal_input_migrate_set_last_info(NULL, info, NULL);
+    qobject_decref(QOBJECT(info));
+
+    return 0;
+}
+
+/*
+ * JSON from the migration source was received - now save it.
+ */
+void qmp_migrate_set_last_info(MigrationInfo *info, Error **errp)
+{
+    MigrationState *s = migrate_get_current();
+
+    if (!info) {
+        fprintf(stderr, "error: migrate-set-last-info dictionary is empty!\n");
+        return;
+    }
+
+    if (!s->last_info) {
+        s->last_info = g_malloc0(sizeof(*s->last_info));
+    } else {
+        g_free(s->last_info->ram);
+    }
+
+    memcpy(s->last_info, info, sizeof(*s->last_info));
+    s->last_info->ram = NULL;
+
+    if (info->has_ram) {
+        s->last_info->ram = g_malloc0(sizeof(*s->last_info->ram));
+        memcpy(s->last_info->ram, info->ram, sizeof(*s->last_info->ram));
+    }
+
+    s->last_info->has_status = false;
+    s->migrated_before = true;
+}
+
+
 MigrationInfo *qmp_query_migrate(Error **errp)
 {
     MigrationInfo *info = g_malloc0(sizeof(*info));
@@ -191,6 +304,11 @@ MigrationInfo *qmp_query_migrate(Error **errp)
     switch (s->state) {
     case MIG_STATE_NONE:
         /* no migration has happened ever */
+        if (s->migrated_before) {
+            memcpy(info, s->last_info, sizeof(*info));
+            info->has_status = true;
+            info->status = g_strdup("last");
+        }
         break;
     case MIG_STATE_SETUP:
         info->has_status = true;
@@ -580,9 +698,10 @@ static void *migration_thread(void *opaque)
     int64_t setup_start = qemu_clock_get_ms(QEMU_CLOCK_HOST);
     int64_t initial_bytes = 0;
     int64_t max_size = 0;
-    int64_t start_time = initial_time;
     bool old_vm_running = false;
 
+    s->start_time = initial_time;
+
     DPRINTF("beginning savevm\n");
     qemu_savevm_state_begin(s->file, &s->params);
 
@@ -607,7 +726,7 @@ static void *migration_thread(void *opaque)
 
                 DPRINTF("done iterating\n");
                 qemu_mutex_lock_iothread();
-                start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
+                s->start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
                 qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
                 old_vm_running = runstate_is_running();
 
@@ -665,9 +784,6 @@ static void *migration_thread(void *opaque)
 
     qemu_mutex_lock_iothread();
     if (s->state == MIG_STATE_COMPLETED) {
-        int64_t end_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
-        s->total_time = end_time - s->total_time;
-        s->downtime = end_time - start_time;
         runstate_set(RUN_STATE_POSTMIGRATE);
     } else {
         if (old_vm_running) {
-- 
1.8.1.2

  parent reply	other threads:[~2014-02-18  5:53 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-02-18  5:53 [Qemu-devel] [RFC PATCH v1 0/3] provenance: save migration stats after completion to destination mrhines
2014-02-18  5:53 ` [Qemu-devel] [RFC PATCH v1 1/3] provenance: QMP command to store MigrationInfo from JSON mrhines
2014-02-18  5:53 ` mrhines [this message]
2014-02-18  5:53 ` [Qemu-devel] [RFC PATCH v1 3/3] provenance: expose the serialization save/load functions for migration mrhines
2014-02-18 13:40 ` [Qemu-devel] [RFC PATCH v1 0/3] provenance: save migration stats after completion to destination Eric Blake
2014-02-19  2:30   ` Michael R. Hines
2014-02-19  2:40     ` Eric Blake
2014-02-19  4:22       ` Michael R. Hines

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1392702802-11592-3-git-send-email-mrhines@linux.vnet.ibm.com \
    --to=mrhines@linux.vnet.ibm.com \
    --cc=hinesmr@cn.ibm.com \
    --cc=mrhines@us.ibm.com \
    --cc=qemu-devel@nongnu.org \
    --cc=quintela@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).