qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 2/8] bitmap dump code via QAPI framework


From: Sanidhya Kashyap
Subject: [Qemu-devel] [PATCH 2/8] bitmap dump code via QAPI framework
Date: Mon, 26 May 2014 12:03:19 +0530

Following are the changes made with respect to the previous version:
Chen's advice
1) Replaced DIRTY_MEMORY_LOG_BITMAP with DIRTY_MEMORY_MIGRATION and
completely removed the DIRTY_MEMORY_LOG_BITMAP flag.

Eric's advice
2) Replaced FILE pointer with file descriptor.
3) Replaced fopen/fclose with qemu_open / qemu_close.
4) Removed text format, output only in machine-readable format.
5) Defined constants.


Signed-off-by: Sanidhya Kashyap <address@hidden>
---
 qapi-schema.json |  17 ++++
 qmp-commands.hx  |  33 ++++++++
 savevm.c         | 246 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 296 insertions(+)

diff --git a/qapi-schema.json b/qapi-schema.json
index 7bc33ea..17e5147 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -4722,3 +4722,20 @@
               'btn'     : 'InputBtnEvent',
               'rel'     : 'InputMoveEvent',
               'abs'     : 'InputMoveEvent' } }
+##
+# @log-dirty-bitmap
+#
+# dumps the dirty bitmap to a file by logging the
+# memory for a specified number of times with a
+# a defined time differnce
+#
+# @filename: name of the file in which the bitmap will be saved.
+# @epochs: number of times the memory will be logged.
+# @frequency: time difference in milliseconds between each epoch.
+#
+# Since 2.1
+##
+{ 'command' : 'log-dirty-bitmap',
+  'data'    : { 'filename'      : 'str',
+                '*epochs'       : 'int',
+                '*frequency'    : 'int' } }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index d8aa4ed..183a636 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -3572,3 +3572,36 @@ Example:
                    } } ] }
 
 EQMP
+
+    {
+        .name       = "log-dirty-bitmap",
+        .args_type  = "filename:s,epochs:i?,frequency:i?,readable:-r?",
+        .mhandler.cmd_new = qmp_marshal_input_log_dirty_bitmap,
+    },
+
+SQMP
+log-dirty-bitmap
+--------------------
+
+start logging the memory of the VM for writable working set
+
+Arguments:
+
+- "filename": name of the file, in which the bitmap will be saved
+- "epochs": number of times, the memory will be logged
+- "frequency": time difference in milliseconds between each epoch
+
+Examples:
+-> { "execute" : "log-dirty-bitmap",
+     "arguments" : {
+         "filename" : "/tmp/fileXXX",
+         "epochs" : 3,
+         "frequency" : 10 } }
+
+<- { "return": {} }
+
+Note: The epochs, frequency and readable are optional. epochs default
+value is 3 while that of frequency is 10.
+
+EQMP
+
diff --git a/savevm.c b/savevm.c
index da8aa24..525b388 100644
--- a/savevm.c
+++ b/savevm.c
@@ -41,6 +41,9 @@
 #include "qemu/iov.h"
 #include "block/snapshot.h"
 #include "block/qapi.h"
+#include "exec/address-spaces.h"
+#include "exec/ram_addr.h"
+#include "qemu/bitmap.h"
 
 #define SELF_ANNOUNCE_ROUNDS 5
 
@@ -1002,6 +1005,249 @@ void do_savevm(Monitor *mon, const QDict *qdict)
     }
 }
 
+/*
+ * Adding the functionality of continuous logging of the
+ * dirty bitmap which is almost similar to the migration
+ * thread
+ */
+
+enum {
+    LOG_BITMAP_STATE_ERROR = -1,
+    LOG_BITMAP_STATE_NONE,
+    LOG_BITMAP_STATE_SETUP,
+    LOG_BITMAP_STATE_ACTIVE,
+    LOG_BITMAP_STATE_CANCELING,
+    LOG_BITMAP_STATE_COMPLETED
+};
+
+typedef struct BitmapLogState BitmapLogState;
+static unsigned long *logging_bitmap;
+static int64_t MIN_EPOCH_VALUE = 3;
+static int64_t MIN_FREQUENCY_VALUE = 10;
+static int64_t LOG_SIZE_MAX = 100000;
+
+struct BitmapLogState {
+    int state;
+    int fd;
+    int64_t current_frequency;
+    int64_t total_epochs;
+    QemuThread thread;
+};
+
+/*
+ * helper functions
+ */
+
+static inline void logging_lock(void)
+{
+    qemu_mutex_lock_iothread();
+    qemu_mutex_lock_ramlist();
+}
+
+static inline void logging_unlock(void)
+{
+    qemu_mutex_unlock_ramlist();
+    qemu_mutex_unlock_iothread();
+}
+
+static inline void logging_bitmap_set_dirty(ram_addr_t addr)
+{
+    int nr  = addr >> TARGET_PAGE_BITS;
+    set_bit(nr, logging_bitmap);
+}
+
+static bool logging_state_set_status(BitmapLogState *b,
+                                     int old_state,
+                                     int new_state)
+{
+    return atomic_cmpxchg(&b->state, old_state, new_state);
+}
+
+static inline bool check_value(int64_t value, int64_t min_value,
+                               const char *str, Error **errp)
+{
+    if (value < min_value) {
+        error_setg(errp, "%s's value must be greater than %ld",
+                         str, min_value);
+        return false;
+    }
+    if (value > LOG_SIZE_MAX) {
+        error_setg(errp, "%s's value must be less than %ld",
+                         str, LOG_SIZE_MAX);
+        return false;
+    }
+    return true;
+}
+
+/*
+ * inspired from migration mechanism
+ */
+
+static BitmapLogState *logging_current_state(void)
+{
+    static BitmapLogState current_bitmaplogstate = {
+        .state = LOG_BITMAP_STATE_NONE,
+    };
+
+    return &current_bitmaplogstate;
+}
+
+/*
+ * syncing the logging_bitmap with the ram_list dirty bitmap
+ */
+
+static void dirty_bitmap_sync(void)
+{
+    RAMBlock *block;
+    address_space_sync_dirty_bitmap(&address_space_memory);
+    QTAILQ_FOREACH(block, &ram_list.blocks, next) {
+        bitmap_sync_range(block->mr->ram_addr, block->length,
+                          logging_bitmap, false);
+    }
+}
+
+static inline void logging_bitmap_close(BitmapLogState *b)
+{
+    logging_lock();
+    memory_global_dirty_log_stop();
+    logging_unlock();
+
+    g_free(logging_bitmap);
+    qemu_close(b->fd);
+    logging_bitmap = NULL;
+    b = NULL;
+}
+
+static void *bitmap_logging_thread(void *opaque)
+{
+    /*
+     * setup basic structures
+     */
+
+    BitmapLogState *b = opaque;
+    int fd = b->fd;
+    int64_t epoch_count = 0;
+    int64_t total_epochs = b->total_epochs;
+    int64_t ram_bitmap_pages = last_ram_offset() >> TARGET_PAGE_BITS;
+    size_t bitmap_size = BITS_TO_LONGS(ram_bitmap_pages) *
+                         sizeof(unsigned long);
+
+    logging_state_set_status(b, LOG_BITMAP_STATE_NONE,
+                                LOG_BITMAP_STATE_SETUP);
+
+    logging_bitmap = bitmap_new(ram_bitmap_pages);
+
+    if (logging_bitmap == NULL) {
+        b->state = LOG_BITMAP_STATE_ERROR;
+        goto log_thread_end;
+    }
+
+    logging_state_set_status(b, LOG_BITMAP_STATE_SETUP,
+                                LOG_BITMAP_STATE_ACTIVE);
+    /*
+     *  start the logging period
+     */
+    logging_lock();
+    memory_global_dirty_log_start();
+    dirty_bitmap_sync();
+    bitmap_zero(logging_bitmap, ram_bitmap_pages);
+    logging_unlock();
+
+    if (qemu_write_full(fd, &ram_bitmap_pages, sizeof(int64_t)) < 0) {
+        b->state = LOG_BITMAP_STATE_ERROR;
+        goto log_thread_end;
+    }
+
+    /*
+     * sync the dirty bitmap along with saving it
+     * using the FILE pointer f.
+     */
+    while (epoch_count < total_epochs) {
+        if (!runstate_is_running() || b->state != LOG_BITMAP_STATE_ACTIVE) {
+            goto log_thread_end;
+        }
+        bitmap_zero(logging_bitmap, ram_bitmap_pages);
+        logging_lock();
+        dirty_bitmap_sync();
+        logging_unlock();
+        if (qemu_write_full(fd, logging_bitmap, bitmap_size) < 0) {
+            b->state = LOG_BITMAP_STATE_ERROR;
+            goto log_thread_end;
+        }
+        g_usleep(b->current_frequency * 1000);
+        epoch_count++;
+    }
+
+    /*
+     * stop the logging period.
+     */
+ log_thread_end:
+    logging_bitmap_close(b);
+    if (b->state == LOG_BITMAP_STATE_ACTIVE) {
+        logging_state_set_status(b, LOG_BITMAP_STATE_ACTIVE,
+                                    LOG_BITMAP_STATE_COMPLETED);
+    } else if (b->state == LOG_BITMAP_STATE_CANCELING) {
+        logging_state_set_status(b, LOG_BITMAP_STATE_CANCELING,
+                                    LOG_BITMAP_STATE_COMPLETED);
+    } else if (b->state == LOG_BITMAP_STATE_ERROR) {
+        logging_state_set_status(b, LOG_BITMAP_STATE_ERROR,
+                                    LOG_BITMAP_STATE_COMPLETED);
+    }
+    return NULL;
+}
+
+void qmp_log_dirty_bitmap(const char *filename, bool has_epochs,
+                          int64_t epochs, bool has_frequency,
+                          int64_t frequency, Error **errp)
+{
+    int fd = -1;
+    BitmapLogState *b = logging_current_state();
+    Error *local_err = NULL;
+    if (b->state == LOG_BITMAP_STATE_ACTIVE ||
+            b->state == LOG_BITMAP_STATE_SETUP ||
+            b->state == LOG_BITMAP_STATE_CANCELING) {
+        b = NULL;
+        error_setg(errp, "dirty bitmap dump in progress");
+        return;
+    }
+
+    if (b->state == LOG_BITMAP_STATE_COMPLETED) {
+        b->state = LOG_BITMAP_STATE_NONE;
+    }
+
+    if (!has_epochs) {
+        epochs = MIN_EPOCH_VALUE;
+    }
+    if (!has_frequency) {
+        frequency = MIN_FREQUENCY_VALUE;
+    }
+
+    if (!check_value(epochs, MIN_EPOCH_VALUE, "epoch", &local_err) ||
+        !check_value(frequency, MIN_FREQUENCY_VALUE, "frequency", &local_err)) 
{
+        if (local_err) {
+            b = NULL;
+            error_propagate(errp, local_err);
+            return;
+        }
+    }
+
+    fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRUSR);
+    if (fd < 0) {
+        error_setg_file_open(errp, errno, filename);
+        b = NULL;
+        return;
+    }
+
+    b->total_epochs = epochs;
+    b->current_frequency = frequency;
+    b->fd = fd;
+    qemu_thread_create(&b->thread, "dirty-bitmap-dump",
+                       bitmap_logging_thread, b,
+                       QEMU_THREAD_JOINABLE);
+
+    return;
+}
+
 void qmp_xen_save_devices_state(const char *filename, Error **errp)
 {
     QEMUFile *f;
-- 
1.8.3.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]