qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v6 00/11] XBRLE delta for live migration of large memory app
@ 2012-01-25 11:26 Orit Wasserman
  2012-01-25 11:26 ` [Qemu-devel] [PATCH v6 01/11] Add cache handling functions Orit Wasserman
                   ` (11 more replies)
  0 siblings, 12 replies; 16+ messages in thread
From: Orit Wasserman @ 2012-01-25 11:26 UTC (permalink / raw)
  To: qemu-devel
  Cc: quintela, Petter Svard, stefanha, blauwirbel, Orit Wasserman,
	Benoit Hudzia, avi, Aidan Shribman

Change from v5:
1) Add migration capabilities
2) Use ULEB to encode run length
3) Do not send unmodified (dirty) page
3) Fix other patch comments

Using GCache or GHashTable requires allocating new buffer on every content change, 
so I decided to keep the simple cache implementation.

Todo :
     Use SSE for encoding
     Automatic activation/deactivation of the feature.

Changes from v4:
1) Rebase
2) divide patch into 9 patches
3) move memory allocation into cache_insert

By using XBZRLE (Xor Based Zero Run Length Encoding) we can reduce VM downtime
and total live-migration time of VMs running memory write intensive workloads
typical of large enterprise applications such as SAP ERP Systems, and generally
speaking for any application with a sparse memory update pattern.

The compression format uses the fact that we will have many zero (zero represents
an unchanged value). 
We repesent the page data delta by zero and non zero runs.
We represent a zero run with it's length (in bytes). 
We represent a non zero run with it's length (in bytes) and the data.
The run length is encoded using ULEB128 (http://en.wikipedia.org/wiki/LEB128)

page = zrun
       | zrun nzrun
       | zrun nzrun page

zrun = length

nzrun = length byte...

length = uleb128 encoded integer

On the sender side XBZRLE is used as a compact delta encoding of page updates,
retrieving the old page content from an LRU cache (default size of 512 MB). The
receiving side uses the existing page content and XBZRLE to decode the new page
content.

This is a more compact way to store the delta than the previous version.

This work was originally based on research results published VEE 2011: Evaluation of
Delta Compression Techniques for Efficient Live Migration of Large Virtual
Machines by Benoit, Svard, Tordsson and Elmroth. Additionally the delta encoder
XBRLE was improved further using XBZRLE instead.

XBZRLE has a sustained bandwidth of 2-2.5 GB/s for typical workloads making it
ideal for in-line, real-time encoding such as is needed for live-migration.

A typical usage scenario:
    {qemu} migrate_set_cachesize 256m
    {qemu} migrate -d -u tcp:destination.host:4444
    {qemu} info migrate
    ...
    transferred ram-duplicate: A kbytes
    transferred ram-duplicate: B pages
    transferred ram-normal: C kbytes
    transferred ram-normal: D pages
    transferred ram-xbrle: E kbytes
    transferred ram-xbrle: F pages
    overflow ram-xbrle: G pages
    cache-hit ram-xbrle: H pages
    cache-lookup ram-xbrle: J pages

Testing: live migration with XBZRLE completed in 110 seconds, without live
migration was not able to complete.

A simple synthetic memory r/w load generator:
..    include <stdlib.h>
..    include <stdio.h>
..    int main()
..    {
..        char *buf = (char *) calloc(4096, 4096);
..        while (1) {
..            int i;
..            for (i = 0; i < 4096 * 4; i++) {
..                buf[i * 4096 / 4]++;
..            }
..            printf(".");
..        }
..    }

Signed-off-by: Benoit Hudzia <benoit.hudzia@sap.com>
Signed-off-by: Petter Svard <petters@cs.umu.se>
Signed-off-by: Aidan Shribman <aidan.shribman@sap.com>

Orit Wasserman (11):
  Add cache handling functions
  Add uleb encoding/decoding functions
  Add save_block_hdr function
  Add host_from_stream_offset_versioned function
  Add XBZRLE to ram_save_block and ram_save_live
  Add MigrationParams structure
  Add XBZRLE parameters to MigrationState
  Add migration capabilties
  Add set_cachesize command
  Add XBZRLE option to migrate command
  Add XBZRLE statstics information

 arch_init.c       |  459 +++++++++++++++++++++++++++++++++++++++++++++++++---
 block-migration.c |    8 +-
 hmp-commands.hx   |   36 ++++-
 hmp.c             |   31 ++++
 hmp.h             |    2 +
 migration.c       |   66 +++++++-
 migration.h       |   31 ++++-
 monitor.c         |    7 +
 qapi-schema.json  |   57 +++++++-
 qemu-common.h     |    1 +
 qmp-commands.hx   |   64 +++++++-
 savevm.c          |  134 +++++++++++++++-
 sysemu.h          |    5 +-
 vmstate.h         |    2 +-
 14 files changed, 837 insertions(+), 66 deletions(-)

-- 
1.7.6.5

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

* [Qemu-devel] [PATCH v6 01/11] Add cache handling functions
  2012-01-25 11:26 [Qemu-devel] [PATCH v6 00/11] XBRLE delta for live migration of large memory app Orit Wasserman
@ 2012-01-25 11:26 ` Orit Wasserman
  2012-01-25 11:26 ` [Qemu-devel] [PATCH v6 02/11] Add uleb encoding/decoding functions Orit Wasserman
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Orit Wasserman @ 2012-01-25 11:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: blauwirbel, stefanha, Orit Wasserman, avi, quintela

Add LRU page caching mechanism.
The pages are stored in the cache ordered by their address.

Signed-off-by: Orit Wasserman <owasserm@redhat.com>
---
 arch_init.c |  175 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 175 insertions(+), 0 deletions(-)

diff --git a/arch_init.c b/arch_init.c
index 95ac682..34e4e60 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -28,6 +28,7 @@
 #include <sys/types.h>
 #include <sys/mman.h>
 #endif
+#include <assert.h>
 #include "config.h"
 #include "monitor.h"
 #include "sysemu.h"
@@ -43,6 +44,14 @@
 #include "hw/smbios.h"
 #include "exec-memory.h"
 
+#ifdef DEBUG_ARCH_INIT
+#define DPRINTF(fmt, ...) \
+    do { fprintf(stdout, "arch_init: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+    do { } while (0)
+#endif
+
 #ifdef TARGET_SPARC
 int graphic_width = 1024;
 int graphic_height = 768;
@@ -126,6 +135,172 @@ static int is_dup_page(uint8_t *page)
     return 1;
 }
 
+/***********************************************************/
+/* Page cache for storing previous pages as basis for XBZRLE compression */
+#define CACHE_N_WAY 2 /* 2-way assossiative cache */
+
+typedef struct CacheItem {
+    ram_addr_t it_addr;
+    unsigned long it_age;
+    uint8_t *it_data;
+} CacheItem;
+
+typedef struct CacheBucket {
+    CacheItem bkt_item[CACHE_N_WAY];
+} CacheBucket;
+
+static CacheBucket *page_cache;
+static int64_t cache_num_buckets;
+static uint64_t cache_max_item_age;
+static int64_t cache_num_items;
+
+static void cache_init(ssize_t num_buckets);
+static void cache_fini(void);
+static int cache_is_cached(ram_addr_t addr);
+static int cache_get_oldest(CacheBucket *buck);
+static int cache_get_newest(CacheBucket *buck, ram_addr_t addr);
+static void cache_insert(ram_addr_t id, uint8_t *pdata);
+static unsigned long cache_get_cache_pos(ram_addr_t address);
+static CacheItem *cache_item_get(unsigned long pos, int item);
+
+/***********************************************************/
+/* XBRLE page cache implementation */
+static CacheItem *cache_item_get(unsigned long pos, int item)
+{
+    assert(page_cache);
+    return &page_cache[pos].bkt_item[item];
+}
+
+static void cache_init(int64_t num_bytes)
+{
+    int i;
+
+    cache_num_items = 0;
+    cache_max_item_age = 0;
+    cache_num_buckets = num_bytes / (TARGET_PAGE_SIZE * CACHE_N_WAY);
+    assert(cache_num_buckets);
+    DPRINTF("Setting cache buckets to %lu\n", cache_num_buckets);
+
+    assert(!page_cache);
+    page_cache = (CacheBucket *)g_malloc((cache_num_buckets) *
+            sizeof(CacheBucket));
+
+    for (i = 0; i < cache_num_buckets; i++) {
+        int j;
+        for (j = 0; j < CACHE_N_WAY; j++) {
+            CacheItem *it = cache_item_get(i, j);
+            it->it_data = NULL;
+            it->it_age = 0;
+            it->it_addr = -1;
+        }
+    }
+}
+
+static void cache_fini(void)
+{
+    int i;
+
+    assert(page_cache);
+
+    for (i = 0; i < cache_num_buckets; i++) {
+        int j;
+        for (j = 0; j < CACHE_N_WAY; j++) {
+            CacheItem *it = cache_item_get(i, j);
+            g_free(it->it_data);
+            it->it_data = 0;
+        }
+    }
+
+    g_free(page_cache);
+    page_cache = NULL;
+}
+
+static unsigned long cache_get_cache_pos(ram_addr_t address)
+{
+    unsigned long pos;
+
+    assert(cache_num_buckets);
+    pos = (address/TARGET_PAGE_SIZE) & (cache_num_buckets - 1);
+    return pos;
+}
+
+static int cache_get_newest(CacheBucket *buck, ram_addr_t addr)
+{
+    unsigned long big = 0;
+    int big_pos = -1;
+    int j;
+
+    assert(page_cache);
+
+    for (j = 0; j < CACHE_N_WAY; j++) {
+        CacheItem *it = &buck->bkt_item[j];
+
+        if (it->it_addr != addr) {
+            continue;
+        }
+
+        if (!j || it->it_age > big) {
+            big = it->it_age;
+            big_pos = j;
+        }
+    }
+
+    return big_pos;
+}
+
+static int cache_get_oldest(CacheBucket *buck)
+{
+    unsigned long small = 0;
+    int small_pos = -1;
+    int j;
+
+    assert(page_cache);
+
+    for (j = 0; j < CACHE_N_WAY; j++) {
+        CacheItem *it = &buck->bkt_item[j];
+
+        if (!j || it->it_age <  small) {
+            small = it->it_age;
+            small_pos = j;
+        }
+    }
+
+    return small_pos;
+}
+
+static int cache_is_cached(ram_addr_t addr)
+{
+    unsigned long pos = cache_get_cache_pos(addr);
+
+    assert(page_cache);
+    CacheBucket *bucket = &page_cache[pos];
+    return cache_get_newest(bucket, addr);
+}
+
+static void cache_insert(unsigned long addr, uint8_t *pdata)
+{
+    unsigned long pos;
+    int slot = -1;
+    CacheBucket *bucket;
+
+    pos = cache_get_cache_pos(addr);
+    assert(page_cache);
+    bucket = &page_cache[pos];
+    slot = cache_get_oldest(bucket); /* evict LRU */
+
+    /* actual update of entry */
+    CacheItem *it = cache_item_get(pos, slot);
+    if (!it->it_data) {
+        it->it_data = g_malloc(TARGET_PAGE_SIZE);
+        cache_num_items++;
+    }
+
+    memcpy(it->it_data, pdata, TARGET_PAGE_SIZE);
+    it->it_age = ++cache_max_item_age;
+    it->it_addr = addr;
+}
+
+
 static RAMBlock *last_block;
 static ram_addr_t last_offset;
 
-- 
1.7.6.5

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

* [Qemu-devel] [PATCH v6 02/11] Add uleb encoding/decoding functions
  2012-01-25 11:26 [Qemu-devel] [PATCH v6 00/11] XBRLE delta for live migration of large memory app Orit Wasserman
  2012-01-25 11:26 ` [Qemu-devel] [PATCH v6 01/11] Add cache handling functions Orit Wasserman
@ 2012-01-25 11:26 ` Orit Wasserman
  2012-01-25 11:48   ` Avi Kivity
  2012-01-25 11:26 ` [Qemu-devel] [PATCH v6 03/11] Add save_block_hdr function Orit Wasserman
                   ` (9 subsequent siblings)
  11 siblings, 1 reply; 16+ messages in thread
From: Orit Wasserman @ 2012-01-25 11:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: blauwirbel, stefanha, Orit Wasserman, avi, quintela

Implement Unsigned Little Endian Base 128.

Signed-off-by: Orit Wasserman <owasserm@redhat.com>
---
 migration.h |    4 ++++
 savevm.c    |   26 ++++++++++++++++++++++++++
 2 files changed, 30 insertions(+), 0 deletions(-)

diff --git a/migration.h b/migration.h
index 372b066..50dec18 100644
--- a/migration.h
+++ b/migration.h
@@ -95,4 +95,8 @@ void migrate_add_blocker(Error *reason);
  */
 void migrate_del_blocker(Error *reason);
 
+/* ULEB128 */
+int uleb128_encode_small(uint8_t *out, uint32_t n);
+int uleb128_decode_small(const uint8 *in, uint32_t *n);
+
 #endif
diff --git a/savevm.c b/savevm.c
index 80be1ff..304db31 100644
--- a/savevm.c
+++ b/savevm.c
@@ -2297,3 +2297,29 @@ void vmstate_register_ram_global(MemoryRegion *mr)
 {
     vmstate_register_ram(mr, NULL);
 }
+
+/* ULEB128 */
+int uleb128_encode_small(uint8_t *out, uint32_t n)
+{
+    if (n < 0x80) {
+        *out++ = n;
+        return 1;
+    } else {
+        *out++ = (n & 0x7f) | 0x80;
+        *out++ = n >> 7;
+    }
+    return 0;
+}
+
+int uleb128_decode_small(const uint8 *in, uint32_t *n)
+{
+    if (!(*in & 0x80)) {
+        *n = *in++;
+        return 1;
+    } else {
+        *n = *in++ & 0x7f;
+        *n |= *in++ << 7;
+        return 0;
+    }
+}
+
-- 
1.7.6.5

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

* [Qemu-devel] [PATCH v6 03/11] Add save_block_hdr function
  2012-01-25 11:26 [Qemu-devel] [PATCH v6 00/11] XBRLE delta for live migration of large memory app Orit Wasserman
  2012-01-25 11:26 ` [Qemu-devel] [PATCH v6 01/11] Add cache handling functions Orit Wasserman
  2012-01-25 11:26 ` [Qemu-devel] [PATCH v6 02/11] Add uleb encoding/decoding functions Orit Wasserman
@ 2012-01-25 11:26 ` Orit Wasserman
  2012-01-25 11:26 ` [Qemu-devel] [PATCH v6 04/11] Add host_from_stream_offset_versioned function Orit Wasserman
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Orit Wasserman @ 2012-01-25 11:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: blauwirbel, stefanha, Orit Wasserman, avi, quintela


Signed-off-by: Orit Wasserman <owasserm@redhat.com>
---
 arch_init.c |   24 ++++++++++++------------
 1 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/arch_init.c b/arch_init.c
index 34e4e60..1218306 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -300,6 +300,16 @@ static void cache_insert(unsigned long addr, uint8_t *pdata)
     it->it_addr = addr;
 }
 
+static void save_block_hdr(QEMUFile *f, RAMBlock *block, ram_addr_t offset,
+        int cont, int flag)
+{
+        qemu_put_be64(f, offset | cont | flag);
+        if (!cont) {
+                qemu_put_byte(f, strlen(block->idstr));
+                qemu_put_buffer(f, (uint8_t *)block->idstr,
+                                strlen(block->idstr));
+        }
+}
 
 static RAMBlock *last_block;
 static ram_addr_t last_offset;
@@ -326,21 +336,11 @@ static int ram_save_block(QEMUFile *f)
             p = memory_region_get_ram_ptr(mr) + offset;
 
             if (is_dup_page(p)) {
-                qemu_put_be64(f, offset | cont | RAM_SAVE_FLAG_COMPRESS);
-                if (!cont) {
-                    qemu_put_byte(f, strlen(block->idstr));
-                    qemu_put_buffer(f, (uint8_t *)block->idstr,
-                                    strlen(block->idstr));
-                }
+                save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_COMPRESS);
                 qemu_put_byte(f, *p);
                 bytes_sent = 1;
             } else {
-                qemu_put_be64(f, offset | cont | RAM_SAVE_FLAG_PAGE);
-                if (!cont) {
-                    qemu_put_byte(f, strlen(block->idstr));
-                    qemu_put_buffer(f, (uint8_t *)block->idstr,
-                                    strlen(block->idstr));
-                }
+                save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_PAGE);
                 qemu_put_buffer(f, p, TARGET_PAGE_SIZE);
                 bytes_sent = TARGET_PAGE_SIZE;
             }
-- 
1.7.6.5

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

* [Qemu-devel] [PATCH v6 04/11] Add host_from_stream_offset_versioned function
  2012-01-25 11:26 [Qemu-devel] [PATCH v6 00/11] XBRLE delta for live migration of large memory app Orit Wasserman
                   ` (2 preceding siblings ...)
  2012-01-25 11:26 ` [Qemu-devel] [PATCH v6 03/11] Add save_block_hdr function Orit Wasserman
@ 2012-01-25 11:26 ` Orit Wasserman
  2012-01-25 11:26 ` [Qemu-devel] [PATCH v6 05/11] Add XBZRLE to ram_save_block and ram_save_live Orit Wasserman
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Orit Wasserman @ 2012-01-25 11:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: blauwirbel, stefanha, Orit Wasserman, avi, quintela


Signed-off-by: Orit Wasserman <owasserm@redhat.com>
---
 arch_init.c |   26 +++++++++++++++++++++++---
 1 files changed, 23 insertions(+), 3 deletions(-)

diff --git a/arch_init.c b/arch_init.c
index 1218306..26312f6 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -550,6 +550,18 @@ static inline void *host_from_stream_offset(QEMUFile *f,
     return NULL;
 }
 
+static inline void *host_from_stream_offset_versioned(int version_id,
+        QEMUFile *f, ram_addr_t offset, int flags)
+{
+        void *host;
+        if (version_id == 3) {
+                host = qemu_get_ram_ptr(offset);
+        } else {
+                host = host_from_stream_offset(f, offset, flags);
+        }
+        return host;
+}
+
 int ram_load(QEMUFile *f, void *opaque, int version_id)
 {
     ram_addr_t addr;
@@ -605,8 +617,11 @@ int ram_load(QEMUFile *f, void *opaque, int version_id)
             void *host;
             uint8_t ch;
 
-            host = host_from_stream_offset(f, addr, flags);
+            host = host_from_stream_offset_versioned(version_id,
+                                                     f, addr, flags);
             if (!host) {
+                fprintf(stderr, "Failed to convert RAM address to host"
+                        " for offset " RAM_ADDR_FMT "\n", addr);
                 return -EINVAL;
             }
 
@@ -621,8 +636,13 @@ int ram_load(QEMUFile *f, void *opaque, int version_id)
         } else if (flags & RAM_SAVE_FLAG_PAGE) {
             void *host;
 
-            host = host_from_stream_offset(f, addr, flags);
-
+            host = host_from_stream_offset_versioned(version_id,
+                                                     f, addr, flags);
+            if (!host) {
+                fprintf(stderr, "Failed to convert RAM address to host"
+                        " for offset " RAM_ADDR_FMT "\n", addr);
+                return -EINVAL;
+            }
             qemu_get_buffer(f, host, TARGET_PAGE_SIZE);
         }
         error = qemu_file_get_error(f);
-- 
1.7.6.5

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

* [Qemu-devel] [PATCH v6 05/11] Add XBZRLE to ram_save_block and ram_save_live
  2012-01-25 11:26 [Qemu-devel] [PATCH v6 00/11] XBRLE delta for live migration of large memory app Orit Wasserman
                   ` (3 preceding siblings ...)
  2012-01-25 11:26 ` [Qemu-devel] [PATCH v6 04/11] Add host_from_stream_offset_versioned function Orit Wasserman
@ 2012-01-25 11:26 ` Orit Wasserman
  2012-01-25 11:26 ` [Qemu-devel] [PATCH v6 06/11] Add MigrationParams structure Orit Wasserman
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Orit Wasserman @ 2012-01-25 11:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: blauwirbel, stefanha, Orit Wasserman, avi, quintela

Add migration state to store XBRLE params (enablement and cache size).
In the outgoing migration check to see if the page is cached and
changed than send compressed page by using save_xbrle_page function.
In the incoming migration check to see if RAM_SAVE_FLAG_XBRLE is set
and decompress the page (by using load_xbrle function).

Signed-off-by: Orit Wasserman <owasserm@redhat.com>
---
 arch_init.c |  169 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 migration.h |    3 +
 savevm.c    |   93 ++++++++++++++++++++++++++++++++-
 3 files changed, 251 insertions(+), 14 deletions(-)

diff --git a/arch_init.c b/arch_init.c
index 26312f6..3a9b0e6 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -103,6 +103,7 @@ const uint32_t arch_type = QEMU_ARCH;
 #define RAM_SAVE_FLAG_PAGE     0x08
 #define RAM_SAVE_FLAG_EOS      0x10
 #define RAM_SAVE_FLAG_CONTINUE 0x20
+#define RAM_SAVE_FLAG_XBZRLE  0x40
 
 #ifdef __ALTIVEC__
 #include <altivec.h>
@@ -163,6 +164,21 @@ static void cache_insert(ram_addr_t id, uint8_t *pdata);
 static unsigned long cache_get_cache_pos(ram_addr_t address);
 static CacheItem *cache_item_get(unsigned long pos, int item);
 
+/* XBZRLE (Xor Based Zero Length Encoding */
+typedef struct XBZRLEHeader {
+    uint8_t xh_flags;
+    uint16_t xh_len;
+    uint32_t xh_cksum;
+} XBZRLEHeader;
+
+/* RAM Migration State */
+typedef struct ArchMigrationState {
+    int use_xbzrle;
+    int64_t xbzrle_cache_size;
+} ArchMigrationState;
+
+static ArchMigrationState arch_mig_state;
+
 /***********************************************************/
 /* XBRLE page cache implementation */
 static CacheItem *cache_item_get(unsigned long pos, int item)
@@ -311,19 +327,66 @@ static void save_block_hdr(QEMUFile *f, RAMBlock *block, ram_addr_t offset,
         }
 }
 
+#define ENCODING_FLAG_XBZRLE 0x1
+
+static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
+                            ram_addr_t current_addr, RAMBlock *block,
+                            ram_addr_t offset, int cont)
+{
+    int cache_location = -1, slot = -1, encoded_len = 0, bytes_sent = 0;
+    XBZRLEHeader hdr = {0};
+    CacheItem *it;
+    uint8_t *encoded_buf = NULL;
+
+    /* get location */
+    slot = cache_is_cached(current_addr);
+    if (slot == -1) {
+        goto done;
+    }
+    cache_location = cache_get_cache_pos(current_addr);
+
+    /* abort if page changed too much */
+    it = cache_item_get(cache_location, slot);
+
+    /* XBZRLE encoding (if there is no overflow) */
+    encoded_buf = (uint8_t *) g_malloc(TARGET_PAGE_SIZE);
+    encoded_len = encode_page(it->it_data, current_data, TARGET_PAGE_SIZE,
+                              encoded_buf, TARGET_PAGE_SIZE);
+    if (encoded_len < 0) {
+        DPRINTF("Unmodifed page - skipping\n");
+        goto done;
+    }
+
+    hdr.xh_len = encoded_len;
+    hdr.xh_flags |= ENCODING_FLAG_XBZRLE;
+
+    /* Send XBZRLE based compressed page */
+    save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_XBZRLE);
+    qemu_put_buffer(f, (uint8_t *) &hdr, sizeof(hdr));
+    qemu_put_buffer(f, encoded_buf, encoded_len);
+    bytes_sent = encoded_len + sizeof(hdr);
+
+done:
+    g_free(encoded_buf);
+    return bytes_sent;
+}
+
 static RAMBlock *last_block;
 static ram_addr_t last_offset;
 
-static int ram_save_block(QEMUFile *f)
+static int ram_save_block(QEMUFile *f, int stage)
 {
     RAMBlock *block = last_block;
     ram_addr_t offset = last_offset;
     int bytes_sent = 0;
     MemoryRegion *mr;
+    ram_addr_t current_addr;
 
     if (!block)
         block = QLIST_FIRST(&ram_list.blocks);
 
+    current_addr = block->offset + offset;
+
     do {
         mr = block->mr;
         if (memory_region_get_dirty(mr, offset, DIRTY_MEMORY_MIGRATION)) {
@@ -339,11 +402,18 @@ static int ram_save_block(QEMUFile *f)
                 save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_COMPRESS);
                 qemu_put_byte(f, *p);
                 bytes_sent = 1;
-            } else {
+            } else if (stage == 2 && arch_mig_state.use_xbzrle) {
+                bytes_sent = save_xbzrle_page(f, p, current_addr, block,
+                    offset, cont);
+            }
+            if (!bytes_sent) {
                 save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_PAGE);
                 qemu_put_buffer(f, p, TARGET_PAGE_SIZE);
                 bytes_sent = TARGET_PAGE_SIZE;
             }
+            if (arch_mig_state.use_xbzrle) {
+                cache_insert(current_addr, p);
+            }
 
             break;
         }
@@ -443,6 +513,9 @@ int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
 
     if (stage < 0) {
         memory_global_dirty_log_stop();
+        if (arch_mig_state.use_xbzrle) {
+            cache_fini();
+        }
         return 0;
     }
 
@@ -455,6 +528,10 @@ int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
         last_offset = 0;
         sort_ram_list();
 
+        if (arch_mig_state.use_xbzrle) {
+            cache_init(arch_mig_state.xbzrle_cache_size);
+        }
+
         /* Make sure all dirty bits are set */
         QLIST_FOREACH(block, &ram_list.blocks, next) {
             for (addr = 0; addr < block->length; addr += TARGET_PAGE_SIZE) {
@@ -482,9 +559,11 @@ int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
     while ((ret = qemu_file_rate_limit(f)) == 0) {
         int bytes_sent;
 
-        bytes_sent = ram_save_block(f);
-        bytes_transferred += bytes_sent;
-        if (bytes_sent == 0) { /* no more blocks */
+        bytes_sent = ram_save_block(f, stage);
+        /* bytes_sent -1 represent unchanged page */
+        if (bytes_sent > 0) {
+            bytes_transferred += bytes_sent;
+        } else if (bytes_sent == 0) { /* no more blocks */
             break;
         }
     }
@@ -507,19 +586,67 @@ int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
         int bytes_sent;
 
         /* flush all remaining blocks regardless of rate limiting */
-        while ((bytes_sent = ram_save_block(f)) != 0) {
+        while ((bytes_sent = ram_save_block(f, stage)) != 0) {
             bytes_transferred += bytes_sent;
         }
         memory_global_dirty_log_stop();
+        if (arch_mig_state.use_xbzrle) {
+            cache_fini();
+        }
     }
 
     qemu_put_be64(f, RAM_SAVE_FLAG_EOS);
 
     expected_time = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth;
 
+    DPRINTF("ram_save_live: expected(%ld) <= max(%ld)?\n", expected_time,
+        migrate_max_downtime());
+
     return (stage == 2) && (expected_time <= migrate_max_downtime());
 }
 
+static int load_xbzrle(QEMUFile *f, ram_addr_t addr, void *host)
+{
+    int ret, rc = -1;
+    uint8_t *xbzrle_buf = NULL;
+    XBZRLEHeader hdr = {0};
+
+    /* extract RLE header */
+    qemu_get_buffer(f, (uint8_t *) &hdr, sizeof(hdr));
+    if (!(hdr.xh_flags & ENCODING_FLAG_XBZRLE)) {
+        fprintf(stderr, "Failed to load XBZRLE page - wrong compression!\n");
+        goto done;
+    }
+
+    if (hdr.xh_len > TARGET_PAGE_SIZE) {
+        fprintf(stderr, "Failed to load XBZRLE page - len overflow!\n");
+        goto done;
+    }
+
+    /* load data and decode */
+    xbzrle_buf = (uint8_t *) g_malloc(TARGET_PAGE_SIZE);
+    qemu_get_buffer(f, xbzrle_buf, hdr.xh_len);
+
+    /* decode RLE */
+    ret = decode_page(xbzrle_buf, hdr.xh_len, host, TARGET_PAGE_SIZE);
+    if (ret == -1) {
+        fprintf(stderr, "Failed to load XBZRLE page - decode error!\n");
+        goto done;
+    }
+
+    if (ret != TARGET_PAGE_SIZE) {
+        fprintf(stderr, "Failed to load XBZRLE page - size %d expected %d!\n",
+            ret, TARGET_PAGE_SIZE);
+        goto done;
+    }
+
+    rc = 0;
+
+done:
+    g_free(xbzrle_buf);
+    return rc;
+}
+
 static inline void *host_from_stream_offset(QEMUFile *f,
                                             ram_addr_t offset,
                                             int flags)
@@ -565,14 +692,18 @@ static inline void *host_from_stream_offset_versioned(int version_id,
 int ram_load(QEMUFile *f, void *opaque, int version_id)
 {
     ram_addr_t addr;
-    int flags;
+    int flags, ret = 0;
     int error;
+    static uint64_t seq_iter;
+
+    seq_iter++;
 
     if (version_id < 4 || version_id > 4) {
         return -EINVAL;
     }
 
     do {
+        void *host;
         addr = qemu_get_be64(f);
 
         flags = addr & ~TARGET_PAGE_MASK;
@@ -596,8 +727,10 @@ int ram_load(QEMUFile *f, void *opaque, int version_id)
 
                     QLIST_FOREACH(block, &ram_list.blocks, next) {
                         if (!strncmp(id, block->idstr, sizeof(id))) {
-                            if (block->length != length)
-                                return -EINVAL;
+                            if (block->length != length) {
+                                ret =  -EINVAL;
+                                goto done;
+                            }
                             break;
                         }
                     }
@@ -605,7 +738,8 @@ int ram_load(QEMUFile *f, void *opaque, int version_id)
                     if (!block) {
                         fprintf(stderr, "Unknown ramblock \"%s\", cannot "
                                 "accept migration\n", id);
-                        return -EINVAL;
+                        ret = -EINVAL;
+                        goto done;
                     }
 
                     total_ram_bytes -= length;
@@ -644,14 +778,25 @@ int ram_load(QEMUFile *f, void *opaque, int version_id)
                 return -EINVAL;
             }
             qemu_get_buffer(f, host, TARGET_PAGE_SIZE);
+        } else if (flags & RAM_SAVE_FLAG_XBZRLE) {
+            host = host_from_stream_offset_versioned(version_id,
+                            f, addr, flags);
+            if (load_xbzrle(f, addr, host) < 0) {
+                ret = -EINVAL;
+                goto done;
+            }
         }
         error = qemu_file_get_error(f);
         if (error) {
-            return error;
+            ret = error;
+            goto done;
         }
     } while (!(flags & RAM_SAVE_FLAG_EOS));
 
-    return 0;
+done:
+    DPRINTF("Completed load of VM with exit code %d seq iteration %ld\n",
+            ret, seq_iter);
+    return ret;
 }
 
 #ifdef HAS_AUDIO
diff --git a/migration.h b/migration.h
index 50dec18..c8cadbc 100644
--- a/migration.h
+++ b/migration.h
@@ -98,5 +98,8 @@ void migrate_del_blocker(Error *reason);
 /* ULEB128 */
 int uleb128_encode_small(uint8_t *out, uint32_t n);
 int uleb128_decode_small(const uint8 *in, uint32_t *n);
+int encode_page(uint8_t *old_buf, uint8_t *new_buf, int slen,
+                uint8_t *dst, int dlen);
+int decode_page(uint8_t *src, int slen, uint8_t *dst, int dlen);
 
 #endif
diff --git a/savevm.c b/savevm.c
index 304db31..cd1c629 100644
--- a/savevm.c
+++ b/savevm.c
@@ -2307,8 +2307,9 @@ int uleb128_encode_small(uint8_t *out, uint32_t n)
     } else {
         *out++ = (n & 0x7f) | 0x80;
         *out++ = n >> 7;
+        return 2;
     }
-    return 0;
+
 }
 
 int uleb128_decode_small(const uint8 *in, uint32_t *n)
@@ -2319,7 +2320,95 @@ int uleb128_decode_small(const uint8 *in, uint32_t *n)
     } else {
         *n = *in++ & 0x7f;
         *n |= *in++ << 7;
-        return 0;
+        return 2;
+    }
+}
+
+/*
+  page = zrun
+       | zrun nzrun
+       | zrun nzrun page
+
+  zrun = length
+
+  nzrun = length byte...
+
+  length = uleb128 encoded integer
+ */
+int encode_page(uint8_t *old_buf, uint8_t *new_buf, int slen, uint8_t *dst,
+                int dlen)
+{
+    uint32_t zrun_len = 0, nzrun_len = 0;
+    int d = 0 , i = 0;
+    uint8_t *nzrun_start = NULL;
+
+    while (i < slen) {
+        /* overflow */
+        if (d + 2 > dlen) {
+            return 0;
+        }
+
+        while (!(old_buf[i] ^ new_buf[i]) && ++i < slen) {
+            zrun_len++;
+        }
+
+        /* buffer unchanged */
+        if (zrun_len == slen) {
+            return -1;
+        }
+
+        d += uleb128_encode_small(dst + d, zrun_len);
+        zrun_len = 0;
+
+        nzrun_start = new_buf + i;
+        while ((old_buf[i] ^ new_buf[i]) != 0 && ++i < slen) {
+            nzrun_len++;
+        }
+
+        /* overflow */
+        if (d + nzrun_len + 2 > dlen) {
+            return 0;
+        }
+
+        d += uleb128_encode_small(dst + d, nzrun_len);
+        memcpy(dst + d, nzrun_start, nzrun_len);
+        d += nzrun_len;
+        nzrun_len = 0;
     }
+
+    return d;
 }
 
+int decode_page(uint8_t *src, int slen, uint8_t *dst, int dlen)
+{
+    int i = 0, d = 0;
+    uint32_t count = 0;
+
+    while (i < slen - 1) {
+        /* zrun */
+        i += uleb128_decode_small(src + i, &count);
+        d += count;
+
+        /* overflow */
+        if (d > dlen) {
+            return -1;
+        }
+
+        /* completed decoding */
+        if (i == slen) {
+            return d + 1;
+        }
+
+        /* nzrun */
+        i += uleb128_decode_small(src + i, &count);
+        /* overflow */
+        if (d + count > dlen) {
+            return -1;
+        }
+        memcpy(dst + d, src + i, count);
+        d += count;
+        i += count;
+    }
+
+    return d + 1;
+}
-- 
1.7.6.5

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

* [Qemu-devel] [PATCH v6 06/11] Add MigrationParams structure
  2012-01-25 11:26 [Qemu-devel] [PATCH v6 00/11] XBRLE delta for live migration of large memory app Orit Wasserman
                   ` (4 preceding siblings ...)
  2012-01-25 11:26 ` [Qemu-devel] [PATCH v6 05/11] Add XBZRLE to ram_save_block and ram_save_live Orit Wasserman
@ 2012-01-25 11:26 ` Orit Wasserman
  2012-01-25 11:26 ` [Qemu-devel] [PATCH v6 07/11] Add XBZRLE parameters to MigrationState Orit Wasserman
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Orit Wasserman @ 2012-01-25 11:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: blauwirbel, stefanha, Orit Wasserman, avi, quintela


Signed-off-by: Orit Wasserman <owasserm@redhat.com>
---
 block-migration.c |    8 ++++----
 migration.c       |   16 +++++++++-------
 migration.h       |    9 +++++++--
 qemu-common.h     |    1 +
 savevm.c          |   12 ++++++++----
 sysemu.h          |    4 ++--
 vmstate.h         |    2 +-
 7 files changed, 32 insertions(+), 20 deletions(-)

diff --git a/block-migration.c b/block-migration.c
index 4467468..69f8c9e 100644
--- a/block-migration.c
+++ b/block-migration.c
@@ -708,13 +708,13 @@ static int block_load(QEMUFile *f, void *opaque, int version_id)
     return 0;
 }
 
-static void block_set_params(int blk_enable, int shared_base, void *opaque)
+static void block_set_params(const MigrationParams *params, void *opaque)
 {
-    block_mig_state.blk_enable = blk_enable;
-    block_mig_state.shared_base = shared_base;
+    block_mig_state.blk_enable = params->blk;
+    block_mig_state.shared_base = params->shared;
 
     /* shared base means that blk_enable = 1 */
-    block_mig_state.blk_enable |= shared_base;
+    block_mig_state.blk_enable |= params->shared;
 }
 
 void blk_mig_init(void)
diff --git a/migration.c b/migration.c
index 37af438..c90740a 100644
--- a/migration.c
+++ b/migration.c
@@ -367,7 +367,7 @@ void migrate_fd_connect(MigrationState *s)
                                       migrate_fd_close);
 
     DPRINTF("beginning savevm\n");
-    ret = qemu_savevm_state_begin(s->mon, s->file, s->blk, s->shared);
+    ret = qemu_savevm_state_begin(s->mon, s->file, &s->params);
     if (ret < 0) {
         DPRINTF("failed, %d\n", ret);
         migrate_fd_error(s);
@@ -376,15 +376,15 @@ void migrate_fd_connect(MigrationState *s)
     migrate_fd_put_ready(s);
 }
 
-static MigrationState *migrate_init(Monitor *mon, int detach, int blk, int inc)
+static MigrationState *migrate_init(Monitor *mon, int detach,
+                                    const MigrationParams *params)
 {
     MigrationState *s = migrate_get_current();
     int64_t bandwidth_limit = s->bandwidth_limit;
 
     memset(s, 0, sizeof(*s));
     s->bandwidth_limit = bandwidth_limit;
-    s->blk = blk;
-    s->shared = inc;
+    s->params = *params;
 
     /* s->mon is used for two things:
        - pass fd in fd migration
@@ -416,13 +416,15 @@ void migrate_del_blocker(Error *reason)
 int do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
     MigrationState *s = migrate_get_current();
+    MigrationParams params;
     const char *p;
     int detach = qdict_get_try_bool(qdict, "detach", 0);
-    int blk = qdict_get_try_bool(qdict, "blk", 0);
-    int inc = qdict_get_try_bool(qdict, "inc", 0);
     const char *uri = qdict_get_str(qdict, "uri");
     int ret;
 
+    params.blk = qdict_get_try_bool(qdict, "blk", 0);
+    params.shared = qdict_get_try_bool(qdict, "inc", 0);
+
     if (s->state == MIG_STATE_ACTIVE) {
         monitor_printf(mon, "migration already in progress\n");
         return -1;
@@ -438,7 +440,7 @@ int do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
         return -1;
     }
 
-    s = migrate_init(mon, detach, blk, inc);
+    s = migrate_init(mon, detach, &params);
 
     if (strstart(uri, "tcp:", &p)) {
         ret = tcp_start_outgoing_migration(s, p);
diff --git a/migration.h b/migration.h
index c8cadbc..6362136 100644
--- a/migration.h
+++ b/migration.h
@@ -19,6 +19,11 @@
 #include "notify.h"
 #include "error.h"
 
+struct MigrationParams {
+    int blk;
+    int shared;
+};
+
 typedef struct MigrationState MigrationState;
 
 struct MigrationState
@@ -32,10 +37,10 @@ struct MigrationState
     int (*close)(MigrationState *s);
     int (*write)(MigrationState *s, const void *buff, size_t size);
     void *opaque;
-    int blk;
-    int shared;
+    MigrationParams params;
 };
 
+
 void process_incoming_migration(QEMUFile *f);
 
 int qemu_start_incoming_migration(const char *uri);
diff --git a/qemu-common.h b/qemu-common.h
index 6ab7dfb..63557c5 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -17,6 +17,7 @@ typedef struct DeviceState DeviceState;
 
 struct Monitor;
 typedef struct Monitor Monitor;
+typedef struct MigrationParams MigrationParams;
 
 /* we put basic includes here to avoid repeating them in device drivers */
 #include <stdlib.h>
diff --git a/savevm.c b/savevm.c
index cd1c629..c3f926d 100644
--- a/savevm.c
+++ b/savevm.c
@@ -1554,8 +1554,8 @@ bool qemu_savevm_state_blocked(Monitor *mon)
     return false;
 }
 
-int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable,
-                            int shared)
+int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f,
+                            const MigrationParams *params)
 {
     SaveStateEntry *se;
     int ret;
@@ -1564,7 +1564,7 @@ int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable,
         if(se->set_params == NULL) {
             continue;
 	}
-	se->set_params(blk_enable, shared, se->opaque);
+        se->set_params(params, se->opaque);
     }
     
     qemu_put_be32(f, QEMU_VM_FILE_MAGIC);
@@ -1702,13 +1702,17 @@ void qemu_savevm_state_cancel(Monitor *mon, QEMUFile *f)
 static int qemu_savevm_state(Monitor *mon, QEMUFile *f)
 {
     int ret;
+    MigrationParams params = {
+        .blk = 0,
+        .shared = 0
+    };
 
     if (qemu_savevm_state_blocked(mon)) {
         ret = -EINVAL;
         goto out;
     }
 
-    ret = qemu_savevm_state_begin(mon, f, 0, 0);
+    ret = qemu_savevm_state_begin(mon, f, &params);
     if (ret < 0)
         goto out;
 
diff --git a/sysemu.h b/sysemu.h
index caff268..f0300d7 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -66,8 +66,8 @@ void do_info_snapshots(Monitor *mon);
 void qemu_announce_self(void);
 
 bool qemu_savevm_state_blocked(Monitor *mon);
-int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable,
-                            int shared);
+int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f,
+                            const MigrationParams *params);
 int qemu_savevm_state_iterate(Monitor *mon, QEMUFile *f);
 int qemu_savevm_state_complete(Monitor *mon, QEMUFile *f);
 void qemu_savevm_state_cancel(Monitor *mon, QEMUFile *f);
diff --git a/vmstate.h b/vmstate.h
index 9d3c49c..f5ef7eb 100644
--- a/vmstate.h
+++ b/vmstate.h
@@ -26,7 +26,7 @@
 #ifndef QEMU_VMSTATE_H
 #define QEMU_VMSTATE_H 1
 
-typedef void SaveSetParamsHandler(int blk_enable, int shared, void * opaque);
+typedef void SaveSetParamsHandler(const MigrationParams *params, void * opaque);
 typedef void SaveStateHandler(QEMUFile *f, void *opaque);
 typedef int SaveLiveStateHandler(Monitor *mon, QEMUFile *f, int stage,
                                  void *opaque);
-- 
1.7.6.5

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

* [Qemu-devel] [PATCH v6 07/11] Add XBZRLE parameters to MigrationState
  2012-01-25 11:26 [Qemu-devel] [PATCH v6 00/11] XBRLE delta for live migration of large memory app Orit Wasserman
                   ` (5 preceding siblings ...)
  2012-01-25 11:26 ` [Qemu-devel] [PATCH v6 06/11] Add MigrationParams structure Orit Wasserman
@ 2012-01-25 11:26 ` Orit Wasserman
  2012-01-25 11:26 ` [Qemu-devel] [PATCH v6 08/11] Add migration capabilties Orit Wasserman
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Orit Wasserman @ 2012-01-25 11:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: blauwirbel, stefanha, Orit Wasserman, avi, quintela


Signed-off-by: Orit Wasserman <owasserm@redhat.com>
---
 arch_init.c |    5 +++++
 migration.c |    8 ++++++++
 migration.h |    4 ++++
 savevm.c    |    9 ++++++---
 sysemu.h    |    1 +
 5 files changed, 24 insertions(+), 3 deletions(-)

diff --git a/arch_init.c b/arch_init.c
index 3a9b0e6..c7da4d7 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -179,6 +179,11 @@ typedef struct ArchMigrationState {
 
 static ArchMigrationState arch_mig_state;
 
+void arch_set_params(const MigrationParams *params, void *opaque)
+{
+    arch_mig_state.use_xbzrle = params->use_xbzrle;
+    arch_mig_state.xbzrle_cache_size = params->xbzrle_cache_size;
+}
 /***********************************************************/
 /* XBRLE page cache implementation */
 static CacheItem *cache_item_get(unsigned long pos, int item)
diff --git a/migration.c b/migration.c
index c90740a..ce039e3 100644
--- a/migration.c
+++ b/migration.c
@@ -43,6 +43,11 @@ enum {
 
 #define MAX_THROTTLE  (32 << 20)      /* Migration speed throttling */
 
+/* Migration XBZRLE cache size */
+#define DEFAULT_MIGRATE_CACHE_SIZE (64 * 1024 * 1024)
+
+static int64_t migrate_cache_size = DEFAULT_MIGRATE_CACHE_SIZE;
+
 static NotifierList migration_state_notifiers =
     NOTIFIER_LIST_INITIALIZER(migration_state_notifiers);
 
@@ -425,6 +430,9 @@ int do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
     params.blk = qdict_get_try_bool(qdict, "blk", 0);
     params.shared = qdict_get_try_bool(qdict, "inc", 0);
 
+    params.use_xbzrle = qdict_get_try_bool(qdict, "xbzrle", 0);
+    params.xbzrle_cache_size =  migrate_cache_size;
+
     if (s->state == MIG_STATE_ACTIVE) {
         monitor_printf(mon, "migration already in progress\n");
         return -1;
diff --git a/migration.h b/migration.h
index 6362136..7e1c7c0 100644
--- a/migration.h
+++ b/migration.h
@@ -22,6 +22,8 @@
 struct MigrationParams {
     int blk;
     int shared;
+    int use_xbzrle;
+    int64_t xbzrle_cache_size;
 };
 
 typedef struct MigrationState MigrationState;
@@ -107,4 +109,6 @@ int encode_page(uint8_t *old_buf, uint8_t *new_buf, int slen,
                 uint8_t *dst, int dlen);
 int decode_page(uint8_t *src, int slen, uint8_t *dst, int dlen);
 
+void arch_set_params(const MigrationParams *params, void *opaque);
+
 #endif
diff --git a/savevm.c b/savevm.c
index c3f926d..f42bb79 100644
--- a/savevm.c
+++ b/savevm.c
@@ -1278,7 +1278,8 @@ int register_savevm(DeviceState *dev,
                     void *opaque)
 {
     return register_savevm_live(dev, idstr, instance_id, version_id,
-                                NULL, NULL, save_state, load_state, opaque);
+                                arch_set_params, NULL, save_state,
+                                load_state, opaque);
 }
 
 void unregister_savevm(DeviceState *dev, const char *idstr, void *opaque)
@@ -1566,7 +1567,7 @@ int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f,
 	}
         se->set_params(params, se->opaque);
     }
-    
+
     qemu_put_be32(f, QEMU_VM_FILE_MAGIC);
     qemu_put_be32(f, QEMU_VM_FILE_VERSION);
 
@@ -1704,7 +1705,9 @@ static int qemu_savevm_state(Monitor *mon, QEMUFile *f)
     int ret;
     MigrationParams params = {
         .blk = 0,
-        .shared = 0
+        .shared = 0,
+        .use_xbzrle = 0,
+        .xbzrle_cache_size = 0
     };
 
     if (qemu_savevm_state_blocked(mon)) {
diff --git a/sysemu.h b/sysemu.h
index f0300d7..bea8aca 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -177,4 +177,5 @@ void register_devices(void);
 void add_boot_device_path(int32_t bootindex, DeviceState *dev,
                           const char *suffix);
 char *get_boot_devices_list(uint32_t *size);
+
 #endif
-- 
1.7.6.5

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

* [Qemu-devel] [PATCH v6 08/11] Add migration capabilties
  2012-01-25 11:26 [Qemu-devel] [PATCH v6 00/11] XBRLE delta for live migration of large memory app Orit Wasserman
                   ` (6 preceding siblings ...)
  2012-01-25 11:26 ` [Qemu-devel] [PATCH v6 07/11] Add XBZRLE parameters to MigrationState Orit Wasserman
@ 2012-01-25 11:26 ` Orit Wasserman
  2012-01-25 11:26 ` [Qemu-devel] [PATCH v6 09/11] Add set_cachesize command Orit Wasserman
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Orit Wasserman @ 2012-01-25 11:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: blauwirbel, stefanha, Orit Wasserman, avi, quintela

Add migration capabiltes that can be queried by the management.
The managment can query to source and the destination in order to 
verfiy both support some maigration capability (currently only XBZRLE).

Signed-off-by: Orit Wasserman <owasserm@redhat.com>
---
 hmp.c            |   18 ++++++++++++++++++
 hmp.h            |    1 +
 migration.c      |   12 ++++++++++++
 monitor.c        |    7 +++++++
 qapi-schema.json |   24 ++++++++++++++++++++++++
 qmp-commands.hx  |   24 ++++++++++++++++++++++++
 6 files changed, 86 insertions(+), 0 deletions(-)

diff --git a/hmp.c b/hmp.c
index 4664dbe..9c41e50 100644
--- a/hmp.c
+++ b/hmp.c
@@ -155,6 +155,24 @@ void hmp_info_migrate(Monitor *mon)
     qapi_free_MigrationInfo(info);
 }
 
+void hmp_info_migration_caps(Monitor *mon)
+{
+    MigrationCapList *caps_list, *cap;
+
+    caps_list = qmp_query_migration_caps(NULL);
+    if (!caps_list) {
+        monitor_printf(mon, "No migration capabilities found\n");
+        return;
+    }
+
+    for (cap = caps_list; cap; cap = cap->next) {
+        monitor_printf(mon, "%s\n", cap->value->name);
+    }
+
+    qapi_free_MigrationCapList(caps_list);
+
+}
+
 void hmp_info_cpus(Monitor *mon)
 {
     CpuInfoList *cpu_list, *cpu;
diff --git a/hmp.h b/hmp.h
index aab0b1f..fdb5b24 100644
--- a/hmp.h
+++ b/hmp.h
@@ -25,6 +25,7 @@ void hmp_info_uuid(Monitor *mon);
 void hmp_info_chardev(Monitor *mon);
 void hmp_info_mice(Monitor *mon);
 void hmp_info_migrate(Monitor *mon);
+void hmp_info_migration_caps(Monitor *mon);
 void hmp_info_cpus(Monitor *mon);
 void hmp_info_block(Monitor *mon);
 void hmp_info_blockstats(Monitor *mon);
diff --git a/migration.c b/migration.c
index ce039e3..b2bb638 100644
--- a/migration.c
+++ b/migration.c
@@ -161,6 +161,17 @@ MigrationInfo *qmp_query_migrate(Error **errp)
     return info;
 }
 
+MigrationCapList *qmp_query_migration_caps(Error **errp)
+{
+    MigrationCapList *caps_list = g_malloc0(sizeof(*caps_list));
+
+    caps_list->value = g_malloc(sizeof(*caps_list->value));
+    caps_list->value->name = g_strdup("uleb");
+    caps_list->next = NULL;
+
+    return caps_list;
+}
+
 /* shared migration helpers */
 
 static void migrate_fd_monitor_suspend(MigrationState *s, Monitor *mon)
@@ -502,3 +513,4 @@ void qmp_migrate_set_downtime(double value, Error **errp)
     value = MAX(0, MIN(UINT64_MAX, value));
     max_downtime = (uint64_t)value;
 }
+
diff --git a/monitor.c b/monitor.c
index 187083c..5742765 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2527,6 +2527,13 @@ static mon_cmd_t info_cmds[] = {
         .mhandler.info = hmp_info_migrate,
     },
     {
+        .name       = "migration_caps",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show migration capabilties",
+        .mhandler.info = hmp_info_migration_caps,
+    },
+    {
         .name       = "balloon",
         .args_type  = "",
         .params     = "",
diff --git a/qapi-schema.json b/qapi-schema.json
index 735eb35..060b7e6 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -276,6 +276,30 @@
 { 'command': 'query-migrate', 'returns': 'MigrationInfo' }
 
 ##
+# @MigrationCap
+#
+# Information about current migration capabilites.
+#
+# @xbzrle: true if the current migration supports xbzrle
+#
+# Since: 1.1
+##
+{ 'type': 'MigrationCap',
+  'data': { 'name': 'str'} }
+
+##
+# @query-migration-caps
+#
+# Returns information about current migration process capabilties.
+#
+# Returns: @MigrationCap
+#
+# Since: 1.1
+##
+{ 'command': 'query-migration-caps', 'returns': ['MigrationCap'] }
+
+
+##
 # @MouseInfo:
 #
 # Information about a mouse device.
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 799e655..e07d2c2 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1955,6 +1955,30 @@ EQMP
     },
 
 SQMP
+query-migration-caps
+-------
+
+Query migration capabilties
+
+- "xbzrle": xbzrle support
+
+Arguments:
+
+Example:
+
+-> { "execute": "query-migration-caps"}
+<- { "return": { "xbzrle" : true } }
+
+EQMP
+
+    {
+        .name       = "query_migration_caps",
+        .args_type  = "",
+	.mhandler.cmd_new = qmp_marshal_input_query_migration_caps,
+    },
+
+
+SQMP
 query-balloon
 -------------
 
-- 
1.7.6.5

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

* [Qemu-devel] [PATCH v6 09/11] Add set_cachesize command
  2012-01-25 11:26 [Qemu-devel] [PATCH v6 00/11] XBRLE delta for live migration of large memory app Orit Wasserman
                   ` (7 preceding siblings ...)
  2012-01-25 11:26 ` [Qemu-devel] [PATCH v6 08/11] Add migration capabilties Orit Wasserman
@ 2012-01-25 11:26 ` Orit Wasserman
  2012-01-25 11:26 ` [Qemu-devel] [PATCH v6 10/11] Add XBZRLE option to migrate command Orit Wasserman
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Orit Wasserman @ 2012-01-25 11:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: blauwirbel, stefanha, Orit Wasserman, avi, quintela

Change XBZRLE cache size in MB (the size should be a poer of 2)

Signed-off-by: Orit Wasserman <owasserm@redhat.com>
---
 hmp-commands.hx  |   15 +++++++++++++++
 hmp.c            |   13 +++++++++++++
 hmp.h            |    1 +
 migration.c      |   22 +++++++++++++++++++++-
 migration.h      |    2 ++
 qapi-schema.json |   13 +++++++++++++
 qmp-commands.hx  |   22 ++++++++++++++++++++++
 7 files changed, 87 insertions(+), 1 deletions(-)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index e6506fc..3b7255d 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -776,6 +776,21 @@ STEXI
 @item migrate_cancel
 @findex migrate_cancel
 Cancel the current VM migration.
+
+ETEXI
+
+    {
+        .name       = "migrate_set_cachesize",
+        .args_type  = "value:o",
+        .params     = "value",
+        .help       = "set cache size (in MB) for XBZRLE migrations",
+        .mhandler.cmd = hmp_migrate_set_cachesize,
+    },
+
+STEXI
+@item migrate_set_cachesize @var{value}
+@findex migrate_set_cache
+Set cache size to @var{value} (in MB) for xbzrle migrations.
 ETEXI
 
     {
diff --git a/hmp.c b/hmp.c
index 9c41e50..9871292 100644
--- a/hmp.c
+++ b/hmp.c
@@ -694,6 +694,19 @@ void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict)
     qmp_migrate_set_downtime(value, NULL);
 }
 
+void hmp_migrate_set_cachesize(Monitor *mon, const QDict *qdict)
+{
+    int64_t value = qdict_get_int(qdict, "value");
+    Error *err = NULL;
+
+    qmp_migrate_set_cachesize(value, &err);
+    if (err) {
+        monitor_printf(mon, "%s\n", error_get_pretty(err));
+        error_free(err);
+        return;
+    }
+}
+
 void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict)
 {
     int64_t value = qdict_get_int(qdict, "value");
diff --git a/hmp.h b/hmp.h
index fdb5b24..ad9f8db 100644
--- a/hmp.h
+++ b/hmp.h
@@ -50,6 +50,7 @@ void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict);
 void hmp_migrate_cancel(Monitor *mon, const QDict *qdict);
 void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict);
 void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict);
+void hmp_migrate_set_cachesize(Monitor *mon, const QDict *qdict);
 void hmp_set_password(Monitor *mon, const QDict *qdict);
 void hmp_expire_password(Monitor *mon, const QDict *qdict);
 void hmp_eject(Monitor *mon, const QDict *qdict);
diff --git a/migration.c b/migration.c
index b2bb638..1cca73f 100644
--- a/migration.c
+++ b/migration.c
@@ -166,7 +166,7 @@ MigrationCapList *qmp_query_migration_caps(Error **errp)
     MigrationCapList *caps_list = g_malloc0(sizeof(*caps_list));
 
     caps_list->value = g_malloc(sizeof(*caps_list->value));
-    caps_list->value->name = g_strdup("uleb");
+    caps_list->value->name = g_strdup("xbzrle");
     caps_list->next = NULL;
 
     return caps_list;
@@ -494,6 +494,26 @@ void qmp_migrate_cancel(Error **errp)
     migrate_fd_cancel(migrate_get_current());
 }
 
+void qmp_migrate_set_cachesize(int64_t value, Error **errp)
+{
+    /* On 32-bit hosts, QEMU is limited by virtual address space */
+    if (value > (2047 << 20) && HOST_LONG_BITS == 32) {
+        error_set(errp, QERR_INVALID_PARAMETER_VALUE, "cache size",
+                  "exceeding address space");
+        return;
+    }
+
+    /* power of 2 */
+    if (value != 1 && (value & (value - 1))) {
+        error_set(errp, QERR_INVALID_PARAMETER_VALUE, "cache size",
+                  "needs to be power of 2");
+        return;
+    }
+
+    value = MIN(UINT64_MAX, value);
+    migrate_cache_size =  value;
+}
+
 void qmp_migrate_set_speed(int64_t value, Error **errp)
 {
     MigrationState *s;
diff --git a/migration.h b/migration.h
index 7e1c7c0..4e53760 100644
--- a/migration.h
+++ b/migration.h
@@ -111,4 +111,6 @@ int decode_page(uint8_t *src, int slen, uint8_t *dst, int dlen);
 
 void arch_set_params(const MigrationParams *params, void *opaque);
 
+void do_migrate_set_cachesize(Monitor *mon, const QDict *qdict);
+
 #endif
diff --git a/qapi-schema.json b/qapi-schema.json
index 060b7e6..cb057d5 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1197,6 +1197,19 @@
 { 'command': 'migrate_set_speed', 'data': {'value': 'int'} }
 
 ##
+# @migrate_set_cachesize
+#
+# Set XBZRLE cache size
+#
+# @value: cache size in Mbytes
+#
+# Returns: nothing on success
+#
+# Since: 1.1
+##
+{ 'command': 'migrate_set_cachesize', 'data': {'value': 'int'} }
+
+##
 # @DevicePropertyInfo:
 #
 # @name: the name of the property
diff --git a/qmp-commands.hx b/qmp-commands.hx
index e07d2c2..ad4e328 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -482,6 +482,28 @@ Example:
 <- { "return": {} }
 
 EQMP
+{
+        .name       = "migrate_set_cachesize",
+        .args_type  = "value:o",
+        .mhandler.cmd_new = qmp_marshal_input_migrate_set_cachesize,
+    },
+
+SQMP
+migrate_set_cachesize
+---------------------
+
+Set cache size to be used by XBZRLE migration
+
+Arguments:
+
+- "value": cache size in bytes (json-int)
+
+Example:
+
+-> { "execute": "migrate_set_cachesize", "arguments": { "value": 512 } }
+<- { "return": {} }
+
+EQMP
 
     {
         .name       = "migrate_set_speed",
-- 
1.7.6.5

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

* [Qemu-devel] [PATCH v6 10/11] Add XBZRLE option to migrate command
  2012-01-25 11:26 [Qemu-devel] [PATCH v6 00/11] XBRLE delta for live migration of large memory app Orit Wasserman
                   ` (8 preceding siblings ...)
  2012-01-25 11:26 ` [Qemu-devel] [PATCH v6 09/11] Add set_cachesize command Orit Wasserman
@ 2012-01-25 11:26 ` Orit Wasserman
  2012-01-25 11:26 ` [Qemu-devel] [PATCH v6 11/11] Add XBZRLE statstics information Orit Wasserman
  2012-01-25 11:53 ` [Qemu-devel] [PATCH v6 00/11] XBRLE delta for live migration of large memory app Avi Kivity
  11 siblings, 0 replies; 16+ messages in thread
From: Orit Wasserman @ 2012-01-25 11:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: blauwirbel, stefanha, Orit Wasserman, avi, quintela

QMP/HMP changes

Signed-off-by: Orit Wasserman <owasserm@redhat.com>
---
 hmp-commands.hx |   21 +++++++++++++--------
 qmp-commands.hx |   18 +++++++++++-------
 2 files changed, 24 insertions(+), 15 deletions(-)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 3b7255d..daa8aae 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -744,24 +744,29 @@ ETEXI
 
     {
         .name       = "migrate",
-        .args_type  = "detach:-d,blk:-b,inc:-i,uri:s",
-        .params     = "[-d] [-b] [-i] uri",
-        .help       = "migrate to URI (using -d to not wait for completion)"
-		      "\n\t\t\t -b for migration without shared storage with"
-		      " full copy of disk\n\t\t\t -i for migration without "
-		      "shared storage with incremental copy of disk "
-		      "(base image shared between src and destination)",
+        .args_type  = "detach:-d,blk:-b,inc:-i,xbzrle:-x,uri:s",
+        .params     = "[-d] [-b] [-i] [-x] uri",
+        .help       = "migrate to URI"
+                      "\n\t -d to not wait for completion"
+                      "\n\t -b for migration without shared storage with"
+                      " full copy of disk"
+                      "\n\t -i for migration without"
+                      " shared storage with incremental copy of disk"
+                      " (base image shared between source and destination)"
+                      "\n\t -x to use XBZRLE page delta compression",
         .user_print = monitor_user_noop,	
 	.mhandler.cmd_new = do_migrate,
     },
 
 
 STEXI
-@item migrate [-d] [-b] [-i] @var{uri}
+@item migrate [-d] [-b] [-i] [-x] @var{uri}
 @findex migrate
 Migrate to @var{uri} (using -d to not wait for completion).
 	-b for migration with full copy of disk
 	-i for migration with incremental copy of disk (base image is shared)
+	-x to use XBZRLE page delta compression
+
 ETEXI
 
     {
diff --git a/qmp-commands.hx b/qmp-commands.hx
index ad4e328..6108de7 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -424,13 +424,16 @@ EQMP
 
     {
         .name       = "migrate",
-        .args_type  = "detach:-d,blk:-b,inc:-i,uri:s",
-        .params     = "[-d] [-b] [-i] uri",
-        .help       = "migrate to URI (using -d to not wait for completion)"
-		      "\n\t\t\t -b for migration without shared storage with"
-		      " full copy of disk\n\t\t\t -i for migration without "
-		      "shared storage with incremental copy of disk "
-		      "(base image shared between src and destination)",
+        .args_type  = "detach:-d,blk:-b,inc:-i,xbzrle:-x,uri:s",
+        .params     = "[-d] [-b] [-i] [-x] uri",
+        .help       = "migrate to URI"
+                      "\n\t -d to not wait for completion"
+                      "\n\t -b for migration without shared storage with"
+                      " full copy of disk"
+                      "\n\t -i for migration without"
+                      " shared storage with incremental copy of disk"
+                      " (base image shared between source and destination)"
+                      "\n\t -x to use XBZRLE page delta compression",
         .user_print = monitor_user_noop,	
 	.mhandler.cmd_new = do_migrate,
     },
@@ -446,6 +449,7 @@ Arguments:
 - "blk": block migration, full disk copy (json-bool, optional)
 - "inc": incremental disk copy (json-bool, optional)
 - "uri": Destination URI (json-string)
+- "xbzrle": to use XBZRLE page delta compression
 
 Example:
 
-- 
1.7.6.5

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

* [Qemu-devel] [PATCH v6 11/11] Add XBZRLE statstics information
  2012-01-25 11:26 [Qemu-devel] [PATCH v6 00/11] XBRLE delta for live migration of large memory app Orit Wasserman
                   ` (9 preceding siblings ...)
  2012-01-25 11:26 ` [Qemu-devel] [PATCH v6 10/11] Add XBZRLE option to migrate command Orit Wasserman
@ 2012-01-25 11:26 ` Orit Wasserman
  2012-01-25 11:53 ` [Qemu-devel] [PATCH v6 00/11] XBRLE delta for live migration of large memory app Avi Kivity
  11 siblings, 0 replies; 16+ messages in thread
From: Orit Wasserman @ 2012-01-25 11:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: blauwirbel, stefanha, Orit Wasserman, avi, quintela


Signed-off-by: Orit Wasserman <owasserm@redhat.com>
---
 arch_init.c      |   60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 migration.c      |   10 +++++++++
 migration.h      |    9 ++++++++
 qapi-schema.json |   20 ++++++++++++++++-
 4 files changed, 97 insertions(+), 2 deletions(-)

diff --git a/arch_init.c b/arch_init.c
index c7da4d7..92f1315 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -184,6 +184,59 @@ void arch_set_params(const MigrationParams *params, void *opaque)
     arch_mig_state.use_xbzrle = params->use_xbzrle;
     arch_mig_state.xbzrle_cache_size = params->xbzrle_cache_size;
 }
+
+/* accounting */
+typedef struct AccountingInfo {
+    uint64_t dup_pages;
+    uint64_t norm_pages;
+    uint64_t xbzrle_bytes;
+    uint64_t xbzrle_pages;
+    uint64_t xbzrle_cache_miss;
+    uint64_t iterations;
+} AccountingInfo;
+
+static AccountingInfo acct_info;
+
+static void acct_clear(void)
+{
+    memset(&acct_info, 0, sizeof(acct_info));
+}
+
+uint64_t dup_mig_bytes_transferred(void)
+{
+    return acct_info.dup_pages * TARGET_PAGE_SIZE;
+}
+
+uint64_t dup_mig_pages_transferred(void)
+{
+    return acct_info.dup_pages;
+}
+
+uint64_t norm_mig_bytes_transferred(void)
+{
+    return acct_info.norm_pages * TARGET_PAGE_SIZE;
+}
+
+uint64_t norm_mig_pages_transferred(void)
+{
+    return acct_info.norm_pages;
+}
+
+uint64_t xbzrle_mig_bytes_transferred(void)
+{
+    return acct_info.xbzrle_bytes;
+}
+
+uint64_t xbzrle_mig_pages_transferred(void)
+{
+    return acct_info.xbzrle_pages;
+}
+
+uint64_t xbzrle_mig_pages_cache_miss(void)
+{
+    return acct_info.xbzrle_cache_miss;
+}
+
 /***********************************************************/
 /* XBRLE page cache implementation */
 static CacheItem *cache_item_get(unsigned long pos, int item)
@@ -346,6 +399,7 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
     /* get location */
     slot = cache_is_cached(current_addr);
     if (slot == -1) {
+        acct_info.xbzrle_cache_miss++;
         goto done;
     }
     cache_location = cache_get_cache_pos(current_addr);
@@ -369,7 +423,9 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
     save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_XBZRLE);
     qemu_put_buffer(f, (uint8_t *) &hdr, sizeof(hdr));
     qemu_put_buffer(f, encoded_buf, encoded_len);
+    acct_info.xbzrle_pages++;
     bytes_sent = encoded_len + sizeof(hdr);
+    acct_info.xbzrle_bytes += bytes_sent;
 
 done:
     g_free(encoded_buf);
@@ -407,6 +463,7 @@ static int ram_save_block(QEMUFile *f, int stage)
                 save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_COMPRESS);
                 qemu_put_byte(f, *p);
                 bytes_sent = 1;
+                acct_info.dup_pages++;
             } else if (stage == 2 && arch_mig_state.use_xbzrle) {
                 bytes_sent = save_xbzrle_page(f, p, current_addr, block,
                     offset, cont);
@@ -415,6 +472,7 @@ static int ram_save_block(QEMUFile *f, int stage)
                 save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_PAGE);
                 qemu_put_buffer(f, p, TARGET_PAGE_SIZE);
                 bytes_sent = TARGET_PAGE_SIZE;
+                 acct_info.norm_pages++;
             }
             if (arch_mig_state.use_xbzrle) {
                 cache_insert(current_addr, p);
@@ -535,6 +593,7 @@ int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
 
         if (arch_mig_state.use_xbzrle) {
             cache_init(arch_mig_state.xbzrle_cache_size);
+            acct_clear();
         }
 
         /* Make sure all dirty bits are set */
@@ -568,6 +627,7 @@ int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
         /* bytes_sent -1 represent unchanged page */
         if (bytes_sent > 0) {
             bytes_transferred += bytes_sent;
+            acct_info.iterations++;
         } else if (bytes_sent == 0) { /* no more blocks */
             break;
         }
diff --git a/migration.c b/migration.c
index 1cca73f..bf59036 100644
--- a/migration.c
+++ b/migration.c
@@ -135,6 +135,8 @@ MigrationInfo *qmp_query_migrate(Error **errp)
         info->ram->transferred = ram_bytes_transferred();
         info->ram->remaining = ram_bytes_remaining();
         info->ram->total = ram_bytes_total();
+        info->ram->duplicate = dup_mig_pages_transferred();
+        info->ram->norm  = norm_mig_pages_transferred();
 
         if (blk_mig_active()) {
             info->has_disk = true;
@@ -143,6 +145,14 @@ MigrationInfo *qmp_query_migrate(Error **errp)
             info->disk->remaining = blk_mig_bytes_remaining();
             info->disk->total = blk_mig_bytes_total();
         }
+
+       if (s->params.use_xbzrle) {
+            info->has_cache = true;
+            info->cache = g_malloc0(sizeof(*info->cache));
+            info->cache->xbzrle_bytes  = xbzrle_mig_bytes_transferred();
+            info->cache->xbzrle_pages  = xbzrle_mig_pages_transferred();
+            info->cache->xbzrle_cache_miss = xbzrle_mig_pages_cache_miss();
+        }
         break;
     case MIG_STATE_COMPLETED:
         info->has_status = true;
diff --git a/migration.h b/migration.h
index 4e53760..5e2e3c9 100644
--- a/migration.h
+++ b/migration.h
@@ -85,6 +85,15 @@ uint64_t ram_bytes_remaining(void);
 uint64_t ram_bytes_transferred(void);
 uint64_t ram_bytes_total(void);
 
+uint64_t dup_mig_bytes_transferred(void);
+uint64_t dup_mig_pages_transferred(void);
+uint64_t norm_mig_bytes_transferred(void);
+uint64_t norm_mig_pages_transferred(void);
+uint64_t xbzrle_mig_bytes_transferred(void);
+uint64_t xbzrle_mig_pages_transferred(void);
+uint64_t xbzrle_mig_pages_overflow(void);
+uint64_t xbzrle_mig_pages_cache_miss(void);
+
 int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque);
 int ram_load(QEMUFile *f, void *opaque, int version_id);
 
diff --git a/qapi-schema.json b/qapi-schema.json
index cb057d5..3e3b239 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -239,7 +239,23 @@
 # Since: 0.14.0.
 ##
 { 'type': 'MigrationStats',
-  'data': {'transferred': 'int', 'remaining': 'int', 'total': 'int' } }
+  'data': {'transferred': 'int', 'remaining': 'int', 'total': 'int', 'duplicate': 'int', 'norm': 'int' } }
+
+##
+# @CacheStats
+#
+# Detailed XBZRLE migration cache statistics
+#
+# @xbzrle_bytes: amount of bytes already transferred to the target VM
+#
+# @xbzrle_pages: amount of pages transferred to the target VM
+#
+# @xbzrle_cache_miss: numer of cache miss
+#
+# Since: 1.1
+##
+{ 'type': 'CacheStats',
+  'data': {'xbzrle_bytes': 'int', 'xbzrle_pages': 'int', 'xbzrle_cache_miss': 'int' } }
 
 ##
 # @MigrationInfo
@@ -262,7 +278,7 @@
 ##
 { 'type': 'MigrationInfo',
   'data': {'*status': 'str', '*ram': 'MigrationStats',
-           '*disk': 'MigrationStats'} }
+           '*disk': 'MigrationStats', '*cache': 'CacheStats'} }
 
 ##
 # @query-migrate
-- 
1.7.6.5

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

* Re: [Qemu-devel] [PATCH v6 02/11] Add uleb encoding/decoding functions
  2012-01-25 11:26 ` [Qemu-devel] [PATCH v6 02/11] Add uleb encoding/decoding functions Orit Wasserman
@ 2012-01-25 11:48   ` Avi Kivity
  2012-01-25 12:22     ` Orit Wasserman
  0 siblings, 1 reply; 16+ messages in thread
From: Avi Kivity @ 2012-01-25 11:48 UTC (permalink / raw)
  To: Orit Wasserman; +Cc: blauwirbel, stefanha, qemu-devel, quintela

On 01/25/2012 01:26 PM, Orit Wasserman wrote:
> Implement Unsigned Little Endian Base 128.
>
>  
> +/* ULEB128 */
> +int uleb128_encode_small(uint8_t *out, uint32_t n);
> +int uleb128_decode_small(const uint8 *in, uint32_t *n);
> +
>  #endif
> diff --git a/savevm.c b/savevm.c
> index 80be1ff..304db31 100644
> --- a/savevm.c
> +++ b/savevm.c
> @@ -2297,3 +2297,29 @@ void vmstate_register_ram_global(MemoryRegion *mr)
>  {
>      vmstate_register_ram(mr, NULL);
>  }
> +
> +/* ULEB128 */
> +int uleb128_encode_small(uint8_t *out, uint32_t n)
> +{

assert(n <= 0x3fff);

> +    if (n < 0x80) {
> +        *out++ = n;
> +        return 1;
> +    } else {
> +        *out++ = (n & 0x7f) | 0x80;
> +        *out++ = n >> 7;

return 2?

> +    }
> +    return 0;
> +}
> +
> +int uleb128_decode_small(const uint8 *in, uint32_t *n)
> +{
> +    if (!(*in & 0x80)) {
> +        *n = *in++;
> +        return 1;
> +    } else {
> +        *n = *in++ & 0x7f;

assert(!(*in & 0x80));

> +        *n |= *in++ << 7;
> +        return 0;

return 2?

> +    }
> +}
> +


-- 
error compiling committee.c: too many arguments to function

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

* Re: [Qemu-devel] [PATCH v6 00/11] XBRLE delta for live migration of large memory app
  2012-01-25 11:26 [Qemu-devel] [PATCH v6 00/11] XBRLE delta for live migration of large memory app Orit Wasserman
                   ` (10 preceding siblings ...)
  2012-01-25 11:26 ` [Qemu-devel] [PATCH v6 11/11] Add XBZRLE statstics information Orit Wasserman
@ 2012-01-25 11:53 ` Avi Kivity
  11 siblings, 0 replies; 16+ messages in thread
From: Avi Kivity @ 2012-01-25 11:53 UTC (permalink / raw)
  To: Orit Wasserman
  Cc: quintela, stefanha, qemu-devel, blauwirbel, Petter Svard,
	Benoit Hudzia, Aidan Shribman

On 01/25/2012 01:26 PM, Orit Wasserman wrote:
> The run length is encoded using ULEB128 (http://en.wikipedia.org/wiki/LEB128)
>
> page = zrun
>        | zrun nzrun
>        | zrun nzrun page
>
> zrun = length
>
> nzrun = length byte...
>
> length = uleb128 encoded integer
>

We can improve this by a further 2 bytes per page by not encoding the
trailing zero run:


  page = zrun nzrun
       | zrun nzrun page

so, a page containing

  { 10*0, 7, 4085*0 }

would be encoded as

  0x10 0x01 0x07

without the trailing 4085 zrun.  This works because you no longer send
unchanged pages.

-- 
error compiling committee.c: too many arguments to function

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

* Re: [Qemu-devel] [PATCH v6 02/11] Add uleb encoding/decoding functions
  2012-01-25 11:48   ` Avi Kivity
@ 2012-01-25 12:22     ` Orit Wasserman
  2012-01-25 12:27       ` Orit Wasserman
  0 siblings, 1 reply; 16+ messages in thread
From: Orit Wasserman @ 2012-01-25 12:22 UTC (permalink / raw)
  To: Avi Kivity; +Cc: qemu-devel

On 01/25/2012 01:48 PM, Avi Kivity wrote:
> On 01/25/2012 01:26 PM, Orit Wasserman wrote:
>> Implement Unsigned Little Endian Base 128.
>>
>>  
>> +/* ULEB128 */
>> +int uleb128_encode_small(uint8_t *out, uint32_t n);
>> +int uleb128_decode_small(const uint8 *in, uint32_t *n);
>> +
>>  #endif
>> diff --git a/savevm.c b/savevm.c
>> index 80be1ff..304db31 100644
>> --- a/savevm.c
>> +++ b/savevm.c
>> @@ -2297,3 +2297,29 @@ void vmstate_register_ram_global(MemoryRegion *mr)
>>  {
>>      vmstate_register_ram(mr, NULL);
>>  }
>> +
>> +/* ULEB128 */
>> +int uleb128_encode_small(uint8_t *out, uint32_t n)
>> +{
> 
> assert(n <= 0x3fff);
> 
>> +    if (n < 0x80) {
>> +        *out++ = n;
>> +        return 1;
>> +    } else {
>> +        *out++ = (n & 0x7f) | 0x80;
>> +        *out++ = n >> 7;
> 
> return 2?
oops , where did it go ...
I will fix it asp.
> 
>> +    }
>> +    return 0;
>> +}
>> +
>> +int uleb128_decode_small(const uint8 *in, uint32_t *n)
>> +{
>> +    if (!(*in & 0x80)) {
>> +        *n = *in++;
>> +        return 1;
>> +    } else {
>> +        *n = *in++ & 0x7f;
> 
> assert(!(*in & 0x80));
> 
>> +        *n |= *in++ << 7;
>> +        return 0;
> 
> return 2?
> 
>> +    }
>> +}
>> +
> 
> 

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

* Re: [Qemu-devel] [PATCH v6 02/11] Add uleb encoding/decoding functions
  2012-01-25 12:22     ` Orit Wasserman
@ 2012-01-25 12:27       ` Orit Wasserman
  0 siblings, 0 replies; 16+ messages in thread
From: Orit Wasserman @ 2012-01-25 12:27 UTC (permalink / raw)
  To: Avi Kivity; +Cc: qemu-devel

On 01/25/2012 02:22 PM, Orit Wasserman wrote:
> On 01/25/2012 01:48 PM, Avi Kivity wrote:
>> On 01/25/2012 01:26 PM, Orit Wasserman wrote:
>>> Implement Unsigned Little Endian Base 128.
>>>
>>>  
>>> +/* ULEB128 */
>>> +int uleb128_encode_small(uint8_t *out, uint32_t n);
>>> +int uleb128_decode_small(const uint8 *in, uint32_t *n);
>>> +
>>>  #endif
>>> diff --git a/savevm.c b/savevm.c
>>> index 80be1ff..304db31 100644
>>> --- a/savevm.c
>>> +++ b/savevm.c
>>> @@ -2297,3 +2297,29 @@ void vmstate_register_ram_global(MemoryRegion *mr)
>>>  {
>>>      vmstate_register_ram(mr, NULL);
>>>  }
>>> +
>>> +/* ULEB128 */
>>> +int uleb128_encode_small(uint8_t *out, uint32_t n)
>>> +{
>>
>> assert(n <= 0x3fff);
>>
>>> +    if (n < 0x80) {
>>> +        *out++ = n;
>>> +        return 1;
>>> +    } else {
>>> +        *out++ = (n & 0x7f) | 0x80;
>>> +        *out++ = n >> 7;
>>
>> return 2?
> oops , where did it go ...
for some reason it is in patch 5 
I will fix the patch series ..

> I will fix it asp.
>>
>>> +    }
>>> +    return 0;
>>> +}
>>> +
>>> +int uleb128_decode_small(const uint8 *in, uint32_t *n)
>>> +{
>>> +    if (!(*in & 0x80)) {
>>> +        *n = *in++;
>>> +        return 1;
>>> +    } else {
>>> +        *n = *in++ & 0x7f;
>>
>> assert(!(*in & 0x80));
>>
>>> +        *n |= *in++ << 7;
>>> +        return 0;
>>
>> return 2?
>>
>>> +    }
>>> +}
>>> +
>>
>>
> 

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

end of thread, other threads:[~2012-01-25 12:28 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-01-25 11:26 [Qemu-devel] [PATCH v6 00/11] XBRLE delta for live migration of large memory app Orit Wasserman
2012-01-25 11:26 ` [Qemu-devel] [PATCH v6 01/11] Add cache handling functions Orit Wasserman
2012-01-25 11:26 ` [Qemu-devel] [PATCH v6 02/11] Add uleb encoding/decoding functions Orit Wasserman
2012-01-25 11:48   ` Avi Kivity
2012-01-25 12:22     ` Orit Wasserman
2012-01-25 12:27       ` Orit Wasserman
2012-01-25 11:26 ` [Qemu-devel] [PATCH v6 03/11] Add save_block_hdr function Orit Wasserman
2012-01-25 11:26 ` [Qemu-devel] [PATCH v6 04/11] Add host_from_stream_offset_versioned function Orit Wasserman
2012-01-25 11:26 ` [Qemu-devel] [PATCH v6 05/11] Add XBZRLE to ram_save_block and ram_save_live Orit Wasserman
2012-01-25 11:26 ` [Qemu-devel] [PATCH v6 06/11] Add MigrationParams structure Orit Wasserman
2012-01-25 11:26 ` [Qemu-devel] [PATCH v6 07/11] Add XBZRLE parameters to MigrationState Orit Wasserman
2012-01-25 11:26 ` [Qemu-devel] [PATCH v6 08/11] Add migration capabilties Orit Wasserman
2012-01-25 11:26 ` [Qemu-devel] [PATCH v6 09/11] Add set_cachesize command Orit Wasserman
2012-01-25 11:26 ` [Qemu-devel] [PATCH v6 10/11] Add XBZRLE option to migrate command Orit Wasserman
2012-01-25 11:26 ` [Qemu-devel] [PATCH v6 11/11] Add XBZRLE statstics information Orit Wasserman
2012-01-25 11:53 ` [Qemu-devel] [PATCH v6 00/11] XBRLE delta for live migration of large memory app Avi Kivity

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