All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v3 0/7] Obtain dirty bitmap via VM logging
@ 2014-06-12 10:36 Sanidhya Kashyap
  2014-06-12 10:36 ` [Qemu-devel] [PATCH v3 1/7] enable sharing of the function between migration and bitmap dump Sanidhya Kashyap
                   ` (7 more replies)
  0 siblings, 8 replies; 10+ messages in thread
From: Sanidhya Kashyap @ 2014-06-12 10:36 UTC (permalink / raw)
  To: qemu list; +Cc: Sanidhya Kashyap, Dr. David Alan Gilbert, Juan Quintela

Hi,

The following patches introduce the support of the dirty bitmap logging and
dumping to a specified file. This patch addresses the issues raised by David
and Juan. Since, I have not received any comments on the runstates, I'll keep
them in the patch series.

v2 --> v3
* Reformatted the code and removed some unnecessary parts.
* Printing block info along with length and offset.
* Changed the functions that were directly using RUN_STATE_RUNNING as state.

v1 --> v2:
* Added two new run states to avoid simultaneous execution of both migration and
  bitmap dump process.
* Removed FILE pointer usage.
* Dumping the data only in machine-readable format.
* Tried to rectify mistakes of the previous version.

Sanidhya Kashyap (7):
  enable sharing of the function between migration and bitmap dump
  RunState: added two new flags for bitmap dump and migration process
  bitmap dump code via QAPI framework with runstates
  hmp interface for dirty bitmap dump
  cancel mechanism for an already running dump bitmap process
  set the frequency of the dump bitmap process
  python script for extracting bitmap from a binary file

 arch_init.c               |  19 +--
 hmp-commands.hx           |  45 ++++++
 hmp.c                     |  33 +++++
 hmp.h                     |   3 +
 hw/usb/hcd-ehci.c         |   2 +-
 hw/usb/redirect.c         |   6 +-
 include/exec/cpu-all.h    |   3 +-
 include/exec/ram_addr.h   |   4 +
 migration.c               |   7 +
 qapi-schema.json          |  44 +++++-
 qmp-commands.hx           |  77 ++++++++++
 savevm.c                  | 357 ++++++++++++++++++++++++++++++++++++++++++++++
 scripts/extract-bitmap.py |  97 +++++++++++++
 vl.c                      |  29 +++-
 14 files changed, 711 insertions(+), 15 deletions(-)
 create mode 100755 scripts/extract-bitmap.py

-- 
1.9.3

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH v3 1/7] enable sharing of the function between migration and bitmap dump
  2014-06-12 10:36 [Qemu-devel] [PATCH v3 0/7] Obtain dirty bitmap via VM logging Sanidhya Kashyap
@ 2014-06-12 10:36 ` Sanidhya Kashyap
  2014-06-12 10:36 ` [Qemu-devel] [PATCH v3 2/7] RunState: added two new flags for bitmap dump and migration process Sanidhya Kashyap
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Sanidhya Kashyap @ 2014-06-12 10:36 UTC (permalink / raw)
  To: qemu list; +Cc: Sanidhya Kashyap, Dr. David Alan Gilbert, Juan Quintela

Added prefix qemu_ to the function as pointed out by Juan.

Signed-off-by: Sanidhya Kashyap <sanidhya.iiith@gmail.com>
---
 arch_init.c             | 19 +++++++++++--------
 include/exec/ram_addr.h |  4 ++++
 2 files changed, 15 insertions(+), 8 deletions(-)

diff --git a/arch_init.c b/arch_init.c
index 23044c1..2fec98b 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -434,20 +434,22 @@ ram_addr_t migration_bitmap_find_and_reset_dirty(MemoryRegion *mr,
     return (next - base) << TARGET_PAGE_BITS;
 }
 
-static inline bool migration_bitmap_set_dirty(ram_addr_t addr)
+static inline bool qemu_bitmap_set_dirty(ram_addr_t addr, unsigned long *bitmap,
+                                                     bool migration_flag)
 {
     bool ret;
     int nr = addr >> TARGET_PAGE_BITS;
 
-    ret = test_and_set_bit(nr, migration_bitmap);
+    ret = test_and_set_bit(nr, bitmap);
 
-    if (!ret) {
+    if (!ret && migration_flag) {
         migration_dirty_pages++;
     }
     return ret;
 }
 
-static void migration_bitmap_sync_range(ram_addr_t start, ram_addr_t length)
+void qemu_bitmap_sync_range(ram_addr_t start, ram_addr_t length,
+                              unsigned long *bitmap, bool migration_flag)
 {
     ram_addr_t addr;
     unsigned long page = BIT_WORD(start >> TARGET_PAGE_BITS);
@@ -461,8 +463,8 @@ static void migration_bitmap_sync_range(ram_addr_t start, ram_addr_t length)
         for (k = page; k < page + nr; k++) {
             if (src[k]) {
                 unsigned long new_dirty;
-                new_dirty = ~migration_bitmap[k];
-                migration_bitmap[k] |= src[k];
+                new_dirty = ~bitmap[k];
+                bitmap[k] |= src[k];
                 new_dirty &= src[k];
                 migration_dirty_pages += ctpopl(new_dirty);
                 src[k] = 0;
@@ -476,7 +478,7 @@ static void migration_bitmap_sync_range(ram_addr_t start, ram_addr_t length)
                 cpu_physical_memory_reset_dirty(start + addr,
                                                 TARGET_PAGE_SIZE,
                                                 DIRTY_MEMORY_MIGRATION);
-                migration_bitmap_set_dirty(start + addr);
+                qemu_bitmap_set_dirty(start + addr, bitmap, migration_flag);
             }
         }
     }
@@ -512,7 +514,8 @@ static void migration_bitmap_sync(void)
     address_space_sync_dirty_bitmap(&address_space_memory);
 
     QTAILQ_FOREACH(block, &ram_list.blocks, next) {
-        migration_bitmap_sync_range(block->mr->ram_addr, block->length);
+        qemu_bitmap_sync_range(block->mr->ram_addr, block->length,
+                          migration_bitmap, true);
     }
     trace_migration_bitmap_sync_end(migration_dirty_pages
                                     - num_dirty_pages_init);
diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
index b94de02..77f7c31 100644
--- a/include/exec/ram_addr.h
+++ b/include/exec/ram_addr.h
@@ -146,5 +146,9 @@ static inline void cpu_physical_memory_clear_dirty_range(ram_addr_t start,
 void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t length,
                                      unsigned client);
 
+
+void qemu_bitmap_sync_range(ram_addr_t start, ram_addr_t length,
+                              unsigned long *bitmap, bool migration_flag);
+
 #endif
 #endif
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH v3 2/7] RunState: added two new flags for bitmap dump and migration process
  2014-06-12 10:36 [Qemu-devel] [PATCH v3 0/7] Obtain dirty bitmap via VM logging Sanidhya Kashyap
  2014-06-12 10:36 ` [Qemu-devel] [PATCH v3 1/7] enable sharing of the function between migration and bitmap dump Sanidhya Kashyap
@ 2014-06-12 10:36 ` Sanidhya Kashyap
  2014-06-12 11:17   ` Sanidhya Kashyap
  2014-06-12 10:36 ` [Qemu-devel] [PATCH v3 3/7] bitmap dump code via QAPI framework with runstates Sanidhya Kashyap
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 10+ messages in thread
From: Sanidhya Kashyap @ 2014-06-12 10:36 UTC (permalink / raw)
  To: qemu list; +Cc: Sanidhya Kashyap, Dr. David Alan Gilbert, Juan Quintela

Changed those files that were directly using the RUN_STATE_RUNNING flag. Now,
they have been replaced by the runstate_is_running() function.

Signed-off-by: Sanidhya Kashyap <sanidhya.iiith@gmail.com>
---
 hw/usb/hcd-ehci.c |  2 +-
 hw/usb/redirect.c |  6 +++---
 qapi-schema.json  |  7 ++++++-
 vl.c              | 29 ++++++++++++++++++++++++++++-
 4 files changed, 38 insertions(+), 6 deletions(-)

diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index a00a93c..5487edc 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -2393,7 +2393,7 @@ static void usb_ehci_vm_state_change(void *opaque, int running, RunState state)
      * USB-devices which have async handled packages have a packet in the
      * ep queue to match the completion with.
      */
-    if (state == RUN_STATE_RUNNING) {
+    if (runstate_is_running()) {
         ehci_advance_async_state(ehci);
     }
 
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index 4c6187b..7023afa 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -283,7 +283,7 @@ static int usbredir_write(void *priv, uint8_t *data, int count)
     }
 
     /* Don't send new data to the chardev until our state is fully synced */
-    if (!runstate_check(RUN_STATE_RUNNING)) {
+    if (!runstate_is_running()) {
         return 0;
     }
 
@@ -1290,7 +1290,7 @@ static int usbredir_chardev_can_read(void *opaque)
     }
 
     /* Don't read new data from the chardev until our state is fully synced */
-    if (!runstate_check(RUN_STATE_RUNNING)) {
+    if (!runstate_is_running()) {
         return 0;
     }
 
@@ -1340,7 +1340,7 @@ static void usbredir_vm_state_change(void *priv, int running, RunState state)
 {
     USBRedirDevice *dev = priv;
 
-    if (state == RUN_STATE_RUNNING && dev->parser != NULL) {
+    if (runstate_is_running() && dev->parser != NULL) {
         usbredirparser_do_write(dev->parser); /* Flush any pending writes */
     }
 }
diff --git a/qapi-schema.json b/qapi-schema.json
index 14b498b..f9c75f9 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -142,12 +142,17 @@
 # @watchdog: the watchdog action is configured to pause and has been triggered
 #
 # @guest-panicked: guest has been panicked as a result of guest OS panic
+#
+# @migrate: migration process is being executed
+#
+# @dump-bitmap: dump the writable working set of the guest
+#
 ##
 { 'enum': 'RunState',
   'data': [ 'debug', 'inmigrate', 'internal-error', 'io-error', 'paused',
             'postmigrate', 'prelaunch', 'finish-migrate', 'restore-vm',
             'running', 'save-vm', 'shutdown', 'suspended', 'watchdog',
-            'guest-panicked' ] }
+            'guest-panicked', 'migrate', 'dump-bitmap' ] }
 
 ##
 # @StatusInfo:
diff --git a/vl.c b/vl.c
index ac0e3d7..08a5c5c 100644
--- a/vl.c
+++ b/vl.c
@@ -576,31 +576,39 @@ static const RunStateTransition runstate_transitions_def[] = {
     /*     from      ->     to      */
     { RUN_STATE_DEBUG, RUN_STATE_RUNNING },
     { RUN_STATE_DEBUG, RUN_STATE_FINISH_MIGRATE },
+    { RUN_STATE_DEBUG, RUN_STATE_MIGRATE },
 
     { RUN_STATE_INMIGRATE, RUN_STATE_RUNNING },
     { RUN_STATE_INMIGRATE, RUN_STATE_PAUSED },
 
     { RUN_STATE_INTERNAL_ERROR, RUN_STATE_PAUSED },
     { RUN_STATE_INTERNAL_ERROR, RUN_STATE_FINISH_MIGRATE },
+    { RUN_STATE_INTERNAL_ERROR, RUN_STATE_MIGRATE },
 
     { RUN_STATE_IO_ERROR, RUN_STATE_RUNNING },
     { RUN_STATE_IO_ERROR, RUN_STATE_FINISH_MIGRATE },
+    { RUN_STATE_IO_ERROR, RUN_STATE_MIGRATE },
 
     { RUN_STATE_PAUSED, RUN_STATE_RUNNING },
     { RUN_STATE_PAUSED, RUN_STATE_FINISH_MIGRATE },
+    { RUN_STATE_PAUSED, RUN_STATE_MIGRATE },
 
     { RUN_STATE_POSTMIGRATE, RUN_STATE_RUNNING },
     { RUN_STATE_POSTMIGRATE, RUN_STATE_FINISH_MIGRATE },
+    { RUN_STATE_POSTMIGRATE, RUN_STATE_MIGRATE },
 
     { RUN_STATE_PRELAUNCH, RUN_STATE_RUNNING },
     { RUN_STATE_PRELAUNCH, RUN_STATE_FINISH_MIGRATE },
     { RUN_STATE_PRELAUNCH, RUN_STATE_INMIGRATE },
+    { RUN_STATE_PRELAUNCH, RUN_STATE_MIGRATE },
 
     { RUN_STATE_FINISH_MIGRATE, RUN_STATE_RUNNING },
     { RUN_STATE_FINISH_MIGRATE, RUN_STATE_POSTMIGRATE },
 
     { RUN_STATE_RESTORE_VM, RUN_STATE_RUNNING },
 
+    { RUN_STATE_DUMP_BITMAP, RUN_STATE_RUNNING},
+
     { RUN_STATE_RUNNING, RUN_STATE_DEBUG },
     { RUN_STATE_RUNNING, RUN_STATE_INTERNAL_ERROR },
     { RUN_STATE_RUNNING, RUN_STATE_IO_ERROR },
@@ -611,6 +619,8 @@ static const RunStateTransition runstate_transitions_def[] = {
     { RUN_STATE_RUNNING, RUN_STATE_SHUTDOWN },
     { RUN_STATE_RUNNING, RUN_STATE_WATCHDOG },
     { RUN_STATE_RUNNING, RUN_STATE_GUEST_PANICKED },
+    { RUN_STATE_RUNNING, RUN_STATE_DUMP_BITMAP },
+    { RUN_STATE_RUNNING, RUN_STATE_MIGRATE },
 
     { RUN_STATE_SAVE_VM, RUN_STATE_RUNNING },
 
@@ -621,12 +631,27 @@ static const RunStateTransition runstate_transitions_def[] = {
     { RUN_STATE_RUNNING, RUN_STATE_SUSPENDED },
     { RUN_STATE_SUSPENDED, RUN_STATE_RUNNING },
     { RUN_STATE_SUSPENDED, RUN_STATE_FINISH_MIGRATE },
+    { RUN_STATE_SUSPENDED, RUN_STATE_MIGRATE },
 
     { RUN_STATE_WATCHDOG, RUN_STATE_RUNNING },
     { RUN_STATE_WATCHDOG, RUN_STATE_FINISH_MIGRATE },
+    { RUN_STATE_WATCHDOG, RUN_STATE_MIGRATE },
 
     { RUN_STATE_GUEST_PANICKED, RUN_STATE_RUNNING },
     { RUN_STATE_GUEST_PANICKED, RUN_STATE_FINISH_MIGRATE },
+    { RUN_STATE_GUEST_PANICKED, RUN_STATE_MIGRATE },
+
+    { RUN_STATE_DUMP_BITMAP, RUN_STATE_RUNNING },
+
+    { RUN_STATE_MIGRATE, RUN_STATE_POSTMIGRATE },
+    { RUN_STATE_MIGRATE, RUN_STATE_PAUSED },
+    { RUN_STATE_MIGRATE, RUN_STATE_SHUTDOWN },
+    { RUN_STATE_MIGRATE, RUN_STATE_GUEST_PANICKED },
+    { RUN_STATE_MIGRATE, RUN_STATE_DEBUG },
+    { RUN_STATE_MIGRATE, RUN_STATE_RUNNING },
+    { RUN_STATE_MIGRATE, RUN_STATE_INTERNAL_ERROR },
+    { RUN_STATE_MIGRATE, RUN_STATE_IO_ERROR },
+    { RUN_STATE_MIGRATE, RUN_STATE_WATCHDOG },
 
     { RUN_STATE_MAX, RUN_STATE_MAX },
 };
@@ -666,7 +691,9 @@ void runstate_set(RunState new_state)
 
 int runstate_is_running(void)
 {
-    return runstate_check(RUN_STATE_RUNNING);
+    return (runstate_check(RUN_STATE_RUNNING) ||
+            runstate_check(RUN_STATE_MIGRATE) ||
+            runstate_check(RUN_STATE_DUMP_BITMAP));
 }
 
 bool runstate_needs_reset(void)
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH v3 3/7] bitmap dump code via QAPI framework with runstates
  2014-06-12 10:36 [Qemu-devel] [PATCH v3 0/7] Obtain dirty bitmap via VM logging Sanidhya Kashyap
  2014-06-12 10:36 ` [Qemu-devel] [PATCH v3 1/7] enable sharing of the function between migration and bitmap dump Sanidhya Kashyap
  2014-06-12 10:36 ` [Qemu-devel] [PATCH v3 2/7] RunState: added two new flags for bitmap dump and migration process Sanidhya Kashyap
@ 2014-06-12 10:36 ` Sanidhya Kashyap
  2014-06-12 10:36 ` [Qemu-devel] [PATCH v3 4/7] hmp interface for dirty bitmap dump Sanidhya Kashyap
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Sanidhya Kashyap @ 2014-06-12 10:36 UTC (permalink / raw)
  To: qemu list; +Cc: Sanidhya Kashyap, Dr. David Alan Gilbert, Juan Quintela

Reformatted the code and added the functionality of dumping the blocks' info
which can be read by the user when required. I have also made the block name
length global.

Signed-off-by: Sanidhya Kashyap <sanidhya.iiith@gmail.com>
---
 include/exec/cpu-all.h |   3 +-
 migration.c            |   7 ++
 qapi-schema.json       |  18 +++
 qmp-commands.hx        |  33 +++++
 savevm.c               | 324 +++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 384 insertions(+), 1 deletion(-)

diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h
index e8363d7..9e6d903 100644
--- a/include/exec/cpu-all.h
+++ b/include/exec/cpu-all.h
@@ -301,6 +301,7 @@ extern ram_addr_t ram_size;
 
 /* RAM is pre-allocated and passed into qemu_ram_alloc_from_ptr */
 #define RAM_PREALLOC_MASK   (1 << 0)
+#define RAMBLOCK_NAME_LENGTH (1<<8)
 
 typedef struct RAMBlock {
     struct MemoryRegion *mr;
@@ -308,7 +309,7 @@ typedef struct RAMBlock {
     ram_addr_t offset;
     ram_addr_t length;
     uint32_t flags;
-    char idstr[256];
+    char idstr[RAMBLOCK_NAME_LENGTH];
     /* Reads can take either the iothread or the ramlist lock.
      * Writes must take both locks.
      */
diff --git a/migration.c b/migration.c
index 3fc03d6..d91dd4c 100644
--- a/migration.c
+++ b/migration.c
@@ -436,6 +436,13 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk,
         return;
     }
 
+    if (runstate_check(RUN_STATE_DUMP_BITMAP)) {
+        error_setg(errp, "bitmap dump in progress");
+        return;
+    }
+
+    runstate_set(RUN_STATE_MIGRATE);
+
     s = migrate_init(&params);
 
     if (strstart(uri, "tcp:", &p)) {
diff --git a/qapi-schema.json b/qapi-schema.json
index f9c75f9..aa78540 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3082,3 +3082,21 @@
               '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..40b6caf 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,327 @@ 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 MAX_EPOCH_VALUE = 100000;
+static int64_t MAX_FREQUENCY_VALUE = 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 value_in_range(int64_t value, int64_t min_value,
+                                  int64_t max_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 > max_value) {
+        error_setg(errp, "%s's value must be less than %ld",
+                         str, max_value);
+        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) {
+        qemu_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);
+    logging_bitmap = NULL;
+    qemu_close(b->fd);
+    b->fd = -1;
+}
+
+static bool ram_block_info_dump(int fd)
+{
+    int64_t ram_bitmap_pages = last_ram_offset() >> TARGET_PAGE_BITS;
+    int block_count = 0;
+    RAMBlock *block;
+    int ret;
+
+    if (qemu_write_full(fd, &ram_bitmap_pages, sizeof(int64_t)) < 0) {
+        return true;
+    }
+
+    QTAILQ_FOREACH(block, &ram_list.blocks, next) {
+        block_count++;
+    }
+
+    ret = qemu_write_full(fd, &block_count, sizeof(int));
+    if (ret < sizeof(int)) {
+    }
+
+    QTAILQ_FOREACH(block, &ram_list.blocks, next) {
+        ret = qemu_write_full(fd, &(block->idstr), sizeof(char) *
+                                                   RAMBLOCK_NAME_LENGTH);
+        if (ret < sizeof(char) * RAMBLOCK_NAME_LENGTH) {
+            return true;
+        }
+        ret = qemu_write_full(fd, &(block->offset), sizeof(ram_addr_t));
+        if (ret < sizeof(ram_addr_t)) {
+            return true;
+        }
+        ret = qemu_write_full(fd, &(block->length), sizeof(ram_addr_t));
+        if (ret < sizeof(ram_addr_t)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+static void logging_state_update_status(BitmapLogState *b)
+{
+    switch (b->state) {
+        case LOG_BITMAP_STATE_ACTIVE:
+            logging_state_set_status(b, LOG_BITMAP_STATE_ACTIVE,
+                                        LOG_BITMAP_STATE_COMPLETED);
+            return;
+        case LOG_BITMAP_STATE_CANCELING:
+            logging_state_set_status(b, LOG_BITMAP_STATE_CANCELING,
+                                        LOG_BITMAP_STATE_COMPLETED);
+            return;
+        case LOG_BITMAP_STATE_ERROR:
+            logging_state_set_status(b, LOG_BITMAP_STATE_ERROR,
+                                        LOG_BITMAP_STATE_COMPLETED);
+    }
+    return;
+}
+
+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);
+    int ret;
+    char marker = 'M';
+
+    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 (ram_block_info_dump(fd)) {
+        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_check(RUN_STATE_DUMP_BITMAP) ||
+            b->state != LOG_BITMAP_STATE_ACTIVE) {
+            goto log_thread_end;
+        }
+        bitmap_zero(logging_bitmap, ram_bitmap_pages);
+        logging_lock();
+        dirty_bitmap_sync();
+        logging_unlock();
+
+        ret = qemu_write_full(fd, logging_bitmap, bitmap_size);
+        if (ret < bitmap_size) {
+            b->state = LOG_BITMAP_STATE_ERROR;
+            goto log_thread_end;
+        }
+
+        ret = qemu_write_full(fd, &marker, sizeof(char));
+        if (ret < sizeof(char)) {
+            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);
+    logging_state_update_status(b);
+    runstate_set(RUN_STATE_RUNNING);
+    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 (runstate_check(RUN_STATE_DUMP_BITMAP) ||
+            b->state == LOG_BITMAP_STATE_ACTIVE ||
+            b->state == LOG_BITMAP_STATE_SETUP ||
+            b->state == LOG_BITMAP_STATE_CANCELING) {
+        error_setg(errp, "dirty bitmap dump in progress");
+        return;
+    }
+
+    if (!runstate_is_running()) {
+        error_setg(errp, "Guest is not in a running state");
+        return;
+    }
+
+    runstate_set(RUN_STATE_DUMP_BITMAP);
+    b->state = LOG_BITMAP_STATE_NONE;
+
+    /*
+     * checking the epoch range
+     */
+    if (!has_epochs) {
+        b->total_epochs = MIN_EPOCH_VALUE;
+    } else if (!value_in_range(epochs, MIN_EPOCH_VALUE,
+                               MAX_EPOCH_VALUE, "epoch", &local_err)) {
+        if (local_err) {
+            error_propagate(errp, local_err);
+        }
+        runstate_set(RUN_STATE_RUNNING);
+        return;
+    } else {
+        b->total_epochs = epochs;
+    }
+
+    /*
+     * checking the frequency range
+     */
+    if (!has_frequency) {
+        b->current_frequency = MIN_FREQUENCY_VALUE;
+    } else if(!value_in_range(frequency, MIN_FREQUENCY_VALUE,
+                              MAX_FREQUENCY_VALUE, "frequency", &local_err)) {
+        if (local_err) {
+            error_propagate(errp, local_err);
+        }
+        runstate_set(RUN_STATE_RUNNING);
+        return;
+    }  else {
+        b->current_frequency = frequency;
+    }
+
+    fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRUSR);
+    if (fd < 0) {
+        error_setg_file_open(errp, errno, filename);
+        runstate_set(RUN_STATE_RUNNING);
+        return;
+    }
+
+    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.9.3

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH v3 4/7] hmp interface for dirty bitmap dump
  2014-06-12 10:36 [Qemu-devel] [PATCH v3 0/7] Obtain dirty bitmap via VM logging Sanidhya Kashyap
                   ` (2 preceding siblings ...)
  2014-06-12 10:36 ` [Qemu-devel] [PATCH v3 3/7] bitmap dump code via QAPI framework with runstates Sanidhya Kashyap
@ 2014-06-12 10:36 ` Sanidhya Kashyap
  2014-06-12 10:36 ` [Qemu-devel] [PATCH v3 5/7] cancel mechanism for an already running dump bitmap process Sanidhya Kashyap
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Sanidhya Kashyap @ 2014-06-12 10:36 UTC (permalink / raw)
  To: qemu list; +Cc: Sanidhya Kashyap, Dr. David Alan Gilbert, Juan Quintela

Signed-off-by: Sanidhya Kashyap <sanidhya.iiith@gmail.com>
---
 hmp-commands.hx | 16 ++++++++++++++++
 hmp.c           | 16 ++++++++++++++++
 hmp.h           |  1 +
 3 files changed, 33 insertions(+)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 5f1a677..cccd53e 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1788,6 +1788,22 @@ STEXI
 show available trace events and their state
 ETEXI
 
+     {
+        .name       = "ldb|log-dirty-bitmap",
+        .args_type  = "filename:s,epochs:i?,frequency:i?",
+        .params     = "filename epochs frequency",
+        .help       = "dumps the memory's dirty bitmap to file\n\t\t\t"
+                     "filename: name of the file in which the bitmap will be saved\n\t\t\t"
+                      "epochs: number of times, the memory will be logged\n\t\t\t"
+                      "frequency: time difference in milliseconds between each epoch",
+        .mhandler.cmd = hmp_log_dirty_bitmap,
+    },
+STEXI
+@item ldb or log-dirty-bitmap @var{filename}
+@findex log-dirty-bitmap
+dumps the writable working set of a VM's memory to a file
+ETEXI
+
 STEXI
 @end table
 ETEXI
diff --git a/hmp.c b/hmp.c
index ccc35d4..a400825 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1314,6 +1314,22 @@ void hmp_device_del(Monitor *mon, const QDict *qdict)
     hmp_handle_error(mon, &err);
 }
 
+void hmp_log_dirty_bitmap(Monitor *mon, const QDict *qdict)
+{
+    const char *filename = qdict_get_str(qdict, "filename");
+    int64_t epochs = qdict_get_try_int(qdict, "epochs", 3);
+    int64_t frequency = qdict_get_try_int(qdict, "frequency", 10);
+    Error *err = NULL;
+
+    qmp_log_dirty_bitmap(filename, !!epochs, epochs, !!frequency,
+                         frequency, &err);
+    if (err) {
+        monitor_printf(mon, "log-dirty-bitmap: %s\n", error_get_pretty(err));
+        error_free(err);
+        return;
+    }
+}
+
 void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict)
 {
     Error *err = NULL;
diff --git a/hmp.h b/hmp.h
index 2d9b0a2..fbb08c5 100644
--- a/hmp.h
+++ b/hmp.h
@@ -93,6 +93,7 @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict);
 void hmp_cpu_add(Monitor *mon, const QDict *qdict);
 void hmp_object_add(Monitor *mon, const QDict *qdict);
 void hmp_object_del(Monitor *mon, const QDict *qdict);
+void hmp_log_dirty_bitmap(Monitor *mon, const QDict *qdict);
 void object_add_completion(ReadLineState *rs, int nb_args, const char *str);
 void object_del_completion(ReadLineState *rs, int nb_args, const char *str);
 void device_add_completion(ReadLineState *rs, int nb_args, const char *str);
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH v3 5/7] cancel mechanism for an already running dump bitmap process
  2014-06-12 10:36 [Qemu-devel] [PATCH v3 0/7] Obtain dirty bitmap via VM logging Sanidhya Kashyap
                   ` (3 preceding siblings ...)
  2014-06-12 10:36 ` [Qemu-devel] [PATCH v3 4/7] hmp interface for dirty bitmap dump Sanidhya Kashyap
@ 2014-06-12 10:36 ` Sanidhya Kashyap
  2014-06-12 10:36 ` [Qemu-devel] [PATCH v3 6/7] set the frequency of the " Sanidhya Kashyap
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Sanidhya Kashyap @ 2014-06-12 10:36 UTC (permalink / raw)
  To: qemu list; +Cc: Sanidhya Kashyap, Dr. David Alan Gilbert, Juan Quintela

Signed-off-by: Sanidhya Kashyap <sanidhya.iiith@gmail.com>
---
 hmp-commands.hx  | 14 ++++++++++++++
 hmp.c            |  5 +++++
 hmp.h            |  1 +
 qapi-schema.json |  8 ++++++++
 qmp-commands.hx  | 20 ++++++++++++++++++++
 savevm.c         | 19 +++++++++++++++++++
 6 files changed, 67 insertions(+)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index cccd53e..a5174ea 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1804,6 +1804,20 @@ STEXI
 dumps the writable working set of a VM's memory to a file
 ETEXI
 
+	{
+	.name       = "ldbc|log-dirty-bitmap-cancel",
+	.args_type  = "",
+	.params     = "",
+	.help       = "cancel the current bitmap dump process",
+	.mhandler.cmd = hmp_log_dirty_bitmap_cancel,
+},
+
+STEXI
+@item ldbc or log-dirty-bitmap-cancel
+@findex log-dirty-bitmap-cancel
+Cancel the current bitmap dump process
+ETEXI
+
 STEXI
 @end table
 ETEXI
diff --git a/hmp.c b/hmp.c
index a400825..fed8795 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1330,6 +1330,11 @@ void hmp_log_dirty_bitmap(Monitor *mon, const QDict *qdict)
     }
 }
 
+void hmp_log_dirty_bitmap_cancel(Monitor *mon, const QDict *qdict)
+{
+    qmp_log_dirty_bitmap_cancel(NULL);
+}
+
 void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict)
 {
     Error *err = NULL;
diff --git a/hmp.h b/hmp.h
index fbb08c5..6d4d672 100644
--- a/hmp.h
+++ b/hmp.h
@@ -94,6 +94,7 @@ void hmp_cpu_add(Monitor *mon, const QDict *qdict);
 void hmp_object_add(Monitor *mon, const QDict *qdict);
 void hmp_object_del(Monitor *mon, const QDict *qdict);
 void hmp_log_dirty_bitmap(Monitor *mon, const QDict *qdict);
+void hmp_log_dirty_bitmap_cancel(Monitor *mon, const QDict *qdict);
 void object_add_completion(ReadLineState *rs, int nb_args, const char *str);
 void object_del_completion(ReadLineState *rs, int nb_args, const char *str);
 void device_add_completion(ReadLineState *rs, int nb_args, const char *str);
diff --git a/qapi-schema.json b/qapi-schema.json
index aa78540..9e07f9d 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3100,3 +3100,11 @@
   'data'    : { 'filename'      : 'str',
                 '*epochs'       : 'int',
                 '*frequency'    : 'int' } }
+##
+# @log-dirty-bitmap-cancel
+#
+# cancel the dirty bitmap logging process
+#
+# Since 2.1
+##
+{ 'command': 'log-dirty-bitmap-cancel' }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 183a636..2a8dacc 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -3605,3 +3605,23 @@ value is 3 while that of frequency is 10.
 
 EQMP
 
+	{
+        .name       = "log-dirty-bitmap-cancel",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_log_dirty_bitmap_cancel,
+    },
+
+SQMP
+log_bitmap_cancel
+--------------
+
+Cancel the current bitmap dump process.
+
+Arguments: None.
+
+Example:
+
+-> { "execute": "log-dirty-bitmap-cancel" }
+<- { "return": {} }
+
+EQMP
diff --git a/savevm.c b/savevm.c
index 40b6caf..e38eca8 100644
--- a/savevm.c
+++ b/savevm.c
@@ -1326,6 +1326,25 @@ void qmp_log_dirty_bitmap(const char *filename, bool has_epochs,
     return;
 }
 
+static void logging_bitmap_cancel(BitmapLogState *b)
+{
+    int old_state;
+    do {
+        old_state = b->state;
+        if (old_state != LOG_BITMAP_STATE_SETUP &&
+            old_state != LOG_BITMAP_STATE_ACTIVE) {
+            break;
+        }
+        logging_state_set_status(b, old_state,
+                                 LOG_BITMAP_STATE_CANCELING);
+    } while (b->state != LOG_BITMAP_STATE_CANCELING);
+}
+
+void qmp_log_dirty_bitmap_cancel(Error **errp)
+{
+    logging_bitmap_cancel(logging_current_state());
+}
+
 void qmp_xen_save_devices_state(const char *filename, Error **errp)
 {
     QEMUFile *f;
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH v3 6/7] set the frequency of the dump bitmap process
  2014-06-12 10:36 [Qemu-devel] [PATCH v3 0/7] Obtain dirty bitmap via VM logging Sanidhya Kashyap
                   ` (4 preceding siblings ...)
  2014-06-12 10:36 ` [Qemu-devel] [PATCH v3 5/7] cancel mechanism for an already running dump bitmap process Sanidhya Kashyap
@ 2014-06-12 10:36 ` Sanidhya Kashyap
  2014-06-12 10:36 ` [Qemu-devel] [PATCH v3 7/7] python script for extracting bitmap from a binary file Sanidhya Kashyap
  2014-06-12 11:47 ` [Qemu-devel] [PATCH v3 3/7][RESEND PATCH] bitmap dump code via QAPI framework with runstates Sanidhya Kashyap
  7 siblings, 0 replies; 10+ messages in thread
From: Sanidhya Kashyap @ 2014-06-12 10:36 UTC (permalink / raw)
  To: qemu list; +Cc: Sanidhya Kashyap, Dr. David Alan Gilbert, Juan Quintela

No, particular change except the function name changed - value_in_range().

Signed-off-by: Sanidhya Kashyap <sanidhya.iiith@gmail.com>
---
 hmp-commands.hx  | 15 +++++++++++++++
 hmp.c            | 12 ++++++++++++
 hmp.h            |  1 +
 qapi-schema.json | 11 +++++++++++
 qmp-commands.hx  | 24 ++++++++++++++++++++++++
 savevm.c         | 14 ++++++++++++++
 6 files changed, 77 insertions(+)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index a5174ea..e6138fa 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1818,6 +1818,21 @@ STEXI
 Cancel the current bitmap dump process
 ETEXI
 
+    {
+        .name       = "ldbsf|log-dirty-bitmap-set-frequency",
+        .args_type  = "frequency:i",
+        .params     = "frequency",
+        .help       = "set the frequency for bitmap dump process\n\t\t\t"
+                      "frequency: the new frequency value to replace the existing",
+        .mhandler.cmd = hmp_log_dirty_bitmap_set_frequency,
+    },
+
+STEXI
+@item ldbsf or log-dirty-bitmap-set-frequency @var{frequency}
+@findex log-dirty-bitmap-set-frequency
+Set the frequency to @var{frequency} (int) for bitmap dump process.
+ETEXI
+
 STEXI
 @end table
 ETEXI
diff --git a/hmp.c b/hmp.c
index fed8795..4dd471d 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1335,6 +1335,18 @@ void hmp_log_dirty_bitmap_cancel(Monitor *mon, const QDict *qdict)
     qmp_log_dirty_bitmap_cancel(NULL);
 }
 
+void hmp_log_dirty_bitmap_set_frequency(Monitor *mon, const QDict *qdict)
+{
+    int64_t frequency = qdict_get_int(qdict, "frequency");
+    Error *err = NULL;
+    qmp_log_dirty_bitmap_set_frequency(frequency, &err);
+    if (err) {
+        monitor_printf(mon, "log-dirty-bitmap-set-frequency: %s\n",
+                       error_get_pretty(err));
+        error_free(err);
+    }
+}
+ 
 void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict)
 {
     Error *err = NULL;
diff --git a/hmp.h b/hmp.h
index 6d4d672..2153e78 100644
--- a/hmp.h
+++ b/hmp.h
@@ -95,6 +95,7 @@ void hmp_object_add(Monitor *mon, const QDict *qdict);
 void hmp_object_del(Monitor *mon, const QDict *qdict);
 void hmp_log_dirty_bitmap(Monitor *mon, const QDict *qdict);
 void hmp_log_dirty_bitmap_cancel(Monitor *mon, const QDict *qdict);
+void hmp_log_dirty_bitmap_set_frequency(Monitor *mon, const QDict *qdict);
 void object_add_completion(ReadLineState *rs, int nb_args, const char *str);
 void object_del_completion(ReadLineState *rs, int nb_args, const char *str);
 void device_add_completion(ReadLineState *rs, int nb_args, const char *str);
diff --git a/qapi-schema.json b/qapi-schema.json
index 9e07f9d..45d7c90 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3108,3 +3108,14 @@
 # Since 2.1
 ##
 { 'command': 'log-dirty-bitmap-cancel' }
+
+## @log-dirty-bitmap-set-frequency
+#
+# sets the frequency of the dirty bitmap logging process
+# @frequency: the updated frequency value
+#
+# Since 2.1
+##
+{ 'command': 'log-dirty-bitmap-set-frequency',
+  'data': {'frequency': 'int' } }
+
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 2a8dacc..f27497a 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -3625,3 +3625,27 @@ Example:
 <- { "return": {} }
 
 EQMP
+
+    {
+        .name       = "log-dirty-bitmap-set-frequency",
+        .args_type  = "frequency:i",
+        .mhandler.cmd_new = qmp_marshal_input_log_dirty_bitmap_set_frequency,
+    },
+
+SQMP
+log-dirty-bitmap-set-frequency
+--------------------
+
+Update the frequency for the remaining epochs.
+
+Arguments:
+
+- "frequency": the updated frequency (json-int)
+
+Example:
+
+-> { "execute": "log-dirty-bitmap-set-frequency", "arguments": { "value": 1024 } }
+<- { "return": {} }
+
+EQMP
+
diff --git a/savevm.c b/savevm.c
index e38eca8..4919cc0 100644
--- a/savevm.c
+++ b/savevm.c
@@ -1345,6 +1345,20 @@ void qmp_log_dirty_bitmap_cancel(Error **errp)
     logging_bitmap_cancel(logging_current_state());
 }
 
+void qmp_log_dirty_bitmap_set_frequency(int64_t frequency, Error **errp)
+{
+    BitmapLogState *b = logging_current_state();
+    Error *local_err = NULL;
+    if (value_in_range(frequency, MIN_FREQUENCY_VALUE,
+                       MAX_FREQUENCY_VALUE, "frequency", &local_err)) {
+        if (local_err) {
+            error_propagate(errp, local_err);
+            return;
+        }
+    }
+    b->current_frequency = frequency;
+}
+
 void qmp_xen_save_devices_state(const char *filename, Error **errp)
 {
     QEMUFile *f;
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH v3 7/7] python script for extracting bitmap from a binary file
  2014-06-12 10:36 [Qemu-devel] [PATCH v3 0/7] Obtain dirty bitmap via VM logging Sanidhya Kashyap
                   ` (5 preceding siblings ...)
  2014-06-12 10:36 ` [Qemu-devel] [PATCH v3 6/7] set the frequency of the " Sanidhya Kashyap
@ 2014-06-12 10:36 ` Sanidhya Kashyap
  2014-06-12 11:47 ` [Qemu-devel] [PATCH v3 3/7][RESEND PATCH] bitmap dump code via QAPI framework with runstates Sanidhya Kashyap
  7 siblings, 0 replies; 10+ messages in thread
From: Sanidhya Kashyap @ 2014-06-12 10:36 UTC (permalink / raw)
  To: qemu list; +Cc: Sanidhya Kashyap, Dr. David Alan Gilbert, Juan Quintela

The script has been modified to store the blocks' information in dictionary
format that can be used by the user. Besides, that there was some issue with
the script which I have rectified and it is working perfectly. For every iteration,
the bitmap is followed by a character - 'M' which acts as a marker identifying
as the end of that bitmap. If the 'M' is missing while reading the file, then
dump is incomplete.

Signed-off-by: Sanidhya Kashyap <sanidhya.iiith@gmail.com>
---
 scripts/extract-bitmap.py | 97 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 97 insertions(+)
 create mode 100755 scripts/extract-bitmap.py

diff --git a/scripts/extract-bitmap.py b/scripts/extract-bitmap.py
new file mode 100755
index 0000000..5edc49d
--- /dev/null
+++ b/scripts/extract-bitmap.py
@@ -0,0 +1,97 @@
+#!/usr/bin/python
+# This python script helps in extracting the dirty bitmap present
+# in the file after executing the log-dirty-bitmap command either
+# from the qmp or hmp interface. This file only processes binary
+# file obtained via command.
+#
+# Copyright (C) 2014 Sanidhya Kashyap <sanidhya.iiith@gmail.com>
+#
+# Authors:
+#       Sanidhya Kashyap
+#
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or later.
+
+import struct
+import argparse
+from functools import partial
+
+long_bytes = 8
+byte_size = 8
+int_bytes = 4
+string_bytes = 256
+complete_bitmap_list = []
+block_list = []
+
+def get_unsigned_long_integer(value):
+	return struct.unpack('<Q', value)[0]
+
+def get_long_integer(value):
+	return struct.unpack('<q', value)[0]
+
+def get_integer(value):
+	return struct.unpack('<i', value)[0]
+
+def get_char(value):
+	return struct.unpack('<c', value)[0]
+
+def get_string(value, length):
+	name = struct.unpack('<'+str(length)+'s', value)[0]
+	for i in range(len(name)):
+		if name[i] == '\x00':
+			return name[:i]
+
+def dump_ram_block_info(infile):
+	total_blocks = get_integer(infile.read(int_bytes))
+	for i in range(total_blocks):
+		block_name = get_string(infile.read(string_bytes), string_bytes)
+		block_offset = get_unsigned_long_integer(infile.read(long_bytes))
+		block_length = get_unsigned_long_integer(infile.read(long_bytes))
+		block_list.append(dict(name=block_name, offset=block_offset, length=block_length))
+	print block_list
+
+def dump_bitmap(infile, bitmap_length):
+	marker = 'M'
+	count = 0
+	value = ' '
+	while True:
+		if len(value) == 0  or marker != 'M':
+			print len(complete_bitmap_list)
+			print "issue with the dump"
+			return
+		bitmap_list = []
+		bitmap_raw_value = infile.read(long_bytes * bitmap_length)
+		if not bitmap_raw_value:
+			print len(bitmap_raw_value)
+			break
+		count+=1
+		for i in range(bitmap_length):
+			mark = i * long_bytes
+			bitmap_list.append(hex(get_unsigned_long_integer(bitmap_raw_value[mark:mark+long_bytes])))
+		complete_bitmap_list.append(bitmap_list)
+		value = infile.read(1)
+		marker = get_char(value)
+	print complete_bitmap_list
+
+def main():
+	extracter = argparse.ArgumentParser(description='Extract dirty bitmap from binary file.')
+	extracter.add_argument('infile', help='Input file to extract the bitmap')
+	args = extracter.parse_args()
+	print 'The filename is {}'.format(args.infile)
+
+	infile = open(format(args.infile), 'rb')
+
+	ram_bitmap_pages = get_long_integer(infile.read(long_bytes))
+	print ram_bitmap_pages
+	dump_ram_block_info(infile)
+	bitmap_length = ram_bitmap_pages / (long_bytes * byte_size)
+	if ram_bitmap_pages % (long_bytes * byte_size) != 0:
+		bitmap_length += 1
+	print bitmap_length
+
+	dump_bitmap(infile, bitmap_length);
+
+	infile.close()
+
+if __name__ == '__main__':
+	main()
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH v3 2/7] RunState: added two new flags for bitmap dump and migration process
  2014-06-12 10:36 ` [Qemu-devel] [PATCH v3 2/7] RunState: added two new flags for bitmap dump and migration process Sanidhya Kashyap
@ 2014-06-12 11:17   ` Sanidhya Kashyap
  0 siblings, 0 replies; 10+ messages in thread
From: Sanidhya Kashyap @ 2014-06-12 11:17 UTC (permalink / raw)
  To: qemu list; +Cc: Sanidhya Kashyap, Dr. David Alan Gilbert, Juan Quintela

>  int runstate_is_running(void)
>  {
> -    return runstate_check(RUN_STATE_RUNNING);
> +    return (runstate_check(RUN_STATE_RUNNING) ||
> +            runstate_check(RUN_STATE_MIGRATE) ||
> +            runstate_check(RUN_STATE_DUMP_BITMAP));
>  }

Forgot to apply the checkpatch script. The return should be without the braces.


-- 

Sanidhya

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH v3 3/7][RESEND PATCH] bitmap dump code via QAPI framework with runstates
  2014-06-12 10:36 [Qemu-devel] [PATCH v3 0/7] Obtain dirty bitmap via VM logging Sanidhya Kashyap
                   ` (6 preceding siblings ...)
  2014-06-12 10:36 ` [Qemu-devel] [PATCH v3 7/7] python script for extracting bitmap from a binary file Sanidhya Kashyap
@ 2014-06-12 11:47 ` Sanidhya Kashyap
  7 siblings, 0 replies; 10+ messages in thread
From: Sanidhya Kashyap @ 2014-06-12 11:47 UTC (permalink / raw)
  To: qemu list; +Cc: Sanidhya Kashyap, Dr. David Alan Gilbert, Juan Quintela

Reformatted the code and added the functionality of dumping the blocks' info
which can be read by the user when required. I have also made the block name
length global.

Signed-off-by: Sanidhya Kashyap <sanidhya.iiith@gmail.com>
---
 include/exec/cpu-all.h |   3 +-
 migration.c            |   7 ++
 qapi-schema.json       |  18 +++
 qmp-commands.hx        |  33 +++++
 savevm.c               | 325 +++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 385 insertions(+), 1 deletion(-)

diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h
index e8363d7..9e6d903 100644
--- a/include/exec/cpu-all.h
+++ b/include/exec/cpu-all.h
@@ -301,6 +301,7 @@ extern ram_addr_t ram_size;
 
 /* RAM is pre-allocated and passed into qemu_ram_alloc_from_ptr */
 #define RAM_PREALLOC_MASK   (1 << 0)
+#define RAMBLOCK_NAME_LENGTH (1<<8)
 
 typedef struct RAMBlock {
     struct MemoryRegion *mr;
@@ -308,7 +309,7 @@ typedef struct RAMBlock {
     ram_addr_t offset;
     ram_addr_t length;
     uint32_t flags;
-    char idstr[256];
+    char idstr[RAMBLOCK_NAME_LENGTH];
     /* Reads can take either the iothread or the ramlist lock.
      * Writes must take both locks.
      */
diff --git a/migration.c b/migration.c
index 3fc03d6..d91dd4c 100644
--- a/migration.c
+++ b/migration.c
@@ -436,6 +436,13 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk,
         return;
     }
 
+    if (runstate_check(RUN_STATE_DUMP_BITMAP)) {
+        error_setg(errp, "bitmap dump in progress");
+        return;
+    }
+
+    runstate_set(RUN_STATE_MIGRATE);
+
     s = migrate_init(&params);
 
     if (strstart(uri, "tcp:", &p)) {
diff --git a/qapi-schema.json b/qapi-schema.json
index f9c75f9..aa78540 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3082,3 +3082,21 @@
               '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..23ba44f 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,328 @@ 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 MAX_EPOCH_VALUE = 100000;
+static int64_t MAX_FREQUENCY_VALUE = 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 value_in_range(int64_t value, int64_t min_value,
+                                  int64_t max_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 > max_value) {
+        error_setg(errp, "%s's value must be less than %ld",
+                         str, max_value);
+        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) {
+        qemu_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);
+    logging_bitmap = NULL;
+    qemu_close(b->fd);
+    b->fd = -1;
+}
+
+static bool ram_block_info_dump(int fd)
+{
+    int64_t ram_bitmap_pages = last_ram_offset() >> TARGET_PAGE_BITS;
+    int block_count = 0;
+    RAMBlock *block;
+    int ret;
+
+    if (qemu_write_full(fd, &ram_bitmap_pages, sizeof(int64_t)) < 0) {
+        return true;
+    }
+
+    QTAILQ_FOREACH(block, &ram_list.blocks, next) {
+        block_count++;
+    }
+
+    ret = qemu_write_full(fd, &block_count, sizeof(int));
+    if (ret < sizeof(int)) {
+        return true;
+    }
+
+    QTAILQ_FOREACH(block, &ram_list.blocks, next) {
+        ret = qemu_write_full(fd, &(block->idstr), sizeof(char) *
+                                                   RAMBLOCK_NAME_LENGTH);
+        if (ret < sizeof(char) * RAMBLOCK_NAME_LENGTH) {
+            return true;
+        }
+        ret = qemu_write_full(fd, &(block->offset), sizeof(ram_addr_t));
+        if (ret < sizeof(ram_addr_t)) {
+            return true;
+        }
+        ret = qemu_write_full(fd, &(block->length), sizeof(ram_addr_t));
+        if (ret < sizeof(ram_addr_t)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+static void logging_state_update_status(BitmapLogState *b)
+{
+    switch (b->state) {
+    case LOG_BITMAP_STATE_ACTIVE:
+        logging_state_set_status(b, LOG_BITMAP_STATE_ACTIVE,
+                                    LOG_BITMAP_STATE_COMPLETED);
+        return;
+    case LOG_BITMAP_STATE_CANCELING:
+        logging_state_set_status(b, LOG_BITMAP_STATE_CANCELING,
+                                    LOG_BITMAP_STATE_COMPLETED);
+        return;
+    case LOG_BITMAP_STATE_ERROR:
+        logging_state_set_status(b, LOG_BITMAP_STATE_ERROR,
+                                    LOG_BITMAP_STATE_COMPLETED);
+    }
+    return;
+}
+
+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);
+    int ret;
+    char marker = 'M';
+
+    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 (ram_block_info_dump(fd)) {
+        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_check(RUN_STATE_DUMP_BITMAP) ||
+            b->state != LOG_BITMAP_STATE_ACTIVE) {
+            goto log_thread_end;
+        }
+        bitmap_zero(logging_bitmap, ram_bitmap_pages);
+        logging_lock();
+        dirty_bitmap_sync();
+        logging_unlock();
+
+        ret = qemu_write_full(fd, logging_bitmap, bitmap_size);
+        if (ret < bitmap_size) {
+            b->state = LOG_BITMAP_STATE_ERROR;
+            goto log_thread_end;
+        }
+
+        ret = qemu_write_full(fd, &marker, sizeof(char));
+        if (ret < sizeof(char)) {
+            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);
+    logging_state_update_status(b);
+    runstate_set(RUN_STATE_RUNNING);
+    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 (runstate_check(RUN_STATE_DUMP_BITMAP) ||
+            b->state == LOG_BITMAP_STATE_ACTIVE ||
+            b->state == LOG_BITMAP_STATE_SETUP ||
+            b->state == LOG_BITMAP_STATE_CANCELING) {
+        error_setg(errp, "dirty bitmap dump in progress");
+        return;
+    }
+
+    if (!runstate_is_running()) {
+        error_setg(errp, "Guest is not in a running state");
+        return;
+    }
+
+    runstate_set(RUN_STATE_DUMP_BITMAP);
+    b->state = LOG_BITMAP_STATE_NONE;
+
+    /*
+     * checking the epoch range
+     */
+    if (!has_epochs) {
+        b->total_epochs = MIN_EPOCH_VALUE;
+    } else if (!value_in_range(epochs, MIN_EPOCH_VALUE,
+                               MAX_EPOCH_VALUE, "epoch", &local_err)) {
+        if (local_err) {
+            error_propagate(errp, local_err);
+        }
+        runstate_set(RUN_STATE_RUNNING);
+        return;
+    } else {
+        b->total_epochs = epochs;
+    }
+
+    /*
+     * checking the frequency range
+     */
+    if (!has_frequency) {
+        b->current_frequency = MIN_FREQUENCY_VALUE;
+    } else if (!value_in_range(frequency, MIN_FREQUENCY_VALUE,
+                               MAX_FREQUENCY_VALUE, "frequency", &local_err)) {
+        if (local_err) {
+            error_propagate(errp, local_err);
+        }
+        runstate_set(RUN_STATE_RUNNING);
+        return;
+    }  else {
+        b->current_frequency = frequency;
+    }
+
+    fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRUSR);
+    if (fd < 0) {
+        error_setg_file_open(errp, errno, filename);
+        runstate_set(RUN_STATE_RUNNING);
+        return;
+    }
+
+    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.9.3

^ permalink raw reply related	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2014-06-12 11:49 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-06-12 10:36 [Qemu-devel] [PATCH v3 0/7] Obtain dirty bitmap via VM logging Sanidhya Kashyap
2014-06-12 10:36 ` [Qemu-devel] [PATCH v3 1/7] enable sharing of the function between migration and bitmap dump Sanidhya Kashyap
2014-06-12 10:36 ` [Qemu-devel] [PATCH v3 2/7] RunState: added two new flags for bitmap dump and migration process Sanidhya Kashyap
2014-06-12 11:17   ` Sanidhya Kashyap
2014-06-12 10:36 ` [Qemu-devel] [PATCH v3 3/7] bitmap dump code via QAPI framework with runstates Sanidhya Kashyap
2014-06-12 10:36 ` [Qemu-devel] [PATCH v3 4/7] hmp interface for dirty bitmap dump Sanidhya Kashyap
2014-06-12 10:36 ` [Qemu-devel] [PATCH v3 5/7] cancel mechanism for an already running dump bitmap process Sanidhya Kashyap
2014-06-12 10:36 ` [Qemu-devel] [PATCH v3 6/7] set the frequency of the " Sanidhya Kashyap
2014-06-12 10:36 ` [Qemu-devel] [PATCH v3 7/7] python script for extracting bitmap from a binary file Sanidhya Kashyap
2014-06-12 11:47 ` [Qemu-devel] [PATCH v3 3/7][RESEND PATCH] bitmap dump code via QAPI framework with runstates Sanidhya Kashyap

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.