Patchwork [RFC,7/6] savevm: Create a new continue flag to avoid resending block name

login
register
mail settings
Submitter Alex Williamson
Date June 8, 2010, 9:11 p.m.
Message ID <20100608211131.10053.73203.stgit@localhost.localdomain>
Download mbox | patch
Permalink /patch/55035/
State New
Headers show

Comments

Alex Williamson - June 8, 2010, 9:11 p.m.
Allows us to compress the protocol a bit.

Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
---

 arch_init.c |   77 +++++++++++++++++++++++++++++++++--------------------------
 1 files changed, 43 insertions(+), 34 deletions(-)
Alex Williamson - June 8, 2010, 9:32 p.m.
On Tue, 2010-06-08 at 15:11 -0600, Alex Williamson wrote:
> Allows us to compress the protocol a bit.
...
> @@ -284,6 +290,33 @@ int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
>      return (stage == 2) && (expected_time <= migrate_max_downtime());
>  }
>  
> +static inline void *host_from_stream_offset(QEMUFile *f,
> +                                            ram_addr_t offset,
> +                                            int flags)

This probably shouldn't be inline.  When sending, we'll continue from
COMPRESS or PAGE.  We'd get out of sync on the recv if the compiler
created separate static blocks.  Compiler folks correct me if this can't
happen.

Alex
Paolo Bonzini - June 8, 2010, 10:29 p.m.
On 06/08/2010 11:32 PM, Alex Williamson wrote:
> On Tue, 2010-06-08 at 15:11 -0600, Alex Williamson wrote:
>> Allows us to compress the protocol a bit.
> ...
>> @@ -284,6 +290,33 @@ int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
>>       return (stage == 2)&&  (expected_time<= migrate_max_downtime());
>>   }
>>
>> +static inline void *host_from_stream_offset(QEMUFile *f,
>> +                                            ram_addr_t offset,
>> +                                            int flags)
>
> This probably shouldn't be inline.  When sending, we'll continue from
> COMPRESS or PAGE.  We'd get out of sync on the recv if the compiler
> created separate static blocks.  Compiler folks correct me if this can't
> happen.

There is only one static variable even if the inlining happens in 
multiple places.  In fact, inlining is totally transparent.

Example:

$ cat > x.c <<\EOF
#ifndef force_inline
#define force_inline inline __attribute__((always_inline))
#endif

static force_inline int f()
{
	static int i;
	return i++;
}

int main()
{
	printf ("%d\n", f());
	printf ("%d\n", f());
	printf ("%d\n", f());
	printf ("%d\n", f());
}
EOF
$ gcc -o - -Dforce_inline= -S x.c | egrep -cw _?f
7
$ gcc -o - -S x.c | egrep -cw _?f
0
$ gcc x.c && ./a.out
0
1
2
3

Paolo

Patch

diff --git a/arch_init.c b/arch_init.c
index 5780195..8ae6a10 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -87,6 +87,7 @@  const uint32_t arch_type = QEMU_ARCH;
 #define RAM_SAVE_FLAG_MEM_SIZE	0x04
 #define RAM_SAVE_FLAG_PAGE	0x08
 #define RAM_SAVE_FLAG_EOS	0x10
+#define RAM_SAVE_FLAG_CONTINUE	0x20
 
 static int is_dup_page(uint8_t *page, uint8_t ch)
 {
@@ -120,6 +121,7 @@  static int ram_save_block(QEMUFile *f)
     do {
         if (cpu_physical_memory_get_dirty(current_addr, MIGRATION_DIRTY_FLAG)) {
             uint8_t *p;
+            int cont = (block == last_block) ? RAM_SAVE_FLAG_CONTINUE : 0;
 
             cpu_physical_memory_reset_dirty(current_addr,
                                             current_addr + TARGET_PAGE_SIZE,
@@ -128,13 +130,17 @@  static int ram_save_block(QEMUFile *f)
             p = block->host + offset;
 
             if (is_dup_page(p, *p)) {
-                qemu_put_be64(f, offset | RAM_SAVE_FLAG_COMPRESS);
-                qemu_put_buffer(f, (uint8_t *)block->name, sizeof(block->name));
+                qemu_put_be64(f, offset | cont | RAM_SAVE_FLAG_COMPRESS);
+                if (!cont)
+                    qemu_put_buffer(f, (uint8_t *)block->name,
+                                    sizeof(block->name));
                 qemu_put_byte(f, *p);
                 bytes_sent = 1;
             } else {
-                qemu_put_be64(f, offset | RAM_SAVE_FLAG_PAGE);
-                qemu_put_buffer(f, (uint8_t *)block->name, sizeof(block->name));
+                qemu_put_be64(f, offset | cont | RAM_SAVE_FLAG_PAGE);
+                if (!cont)
+                    qemu_put_buffer(f, (uint8_t *)block->name,
+                                    sizeof(block->name));
                 qemu_put_buffer(f, p, TARGET_PAGE_SIZE);
                 bytes_sent = TARGET_PAGE_SIZE;
             }
@@ -284,6 +290,33 @@  int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
     return (stage == 2) && (expected_time <= migrate_max_downtime());
 }
 
+static inline void *host_from_stream_offset(QEMUFile *f,
+                                            ram_addr_t offset,
+                                            int flags)
+{
+    static RAMBlock *block = NULL;
+    char name[64];
+
+    if (flags & RAM_SAVE_FLAG_CONTINUE) {
+        if (!block) {
+            fprintf(stderr, "Ack, bad migration stream!\n");
+            return NULL;
+        }
+
+        return block->host + offset;
+    }
+
+    qemu_get_buffer(f, (uint8_t *)name, sizeof(name));
+
+    QLIST_FOREACH(block, &ram.blocks, next) {
+        if (!strncmp(name, block->name, sizeof(name)))
+            return block->host + offset;
+    }
+
+    fprintf(stderr, "Can't find block %s!\n", name);
+    return NULL;
+}
+
 int ram_load(QEMUFile *f, void *opaque, int version_id)
 {
     ram_addr_t addr;
@@ -337,23 +370,11 @@  int ram_load(QEMUFile *f, void *opaque, int version_id)
             void *host;
             uint8_t ch;
 
-            if (version_id == 3) {
+            if (version_id == 3)
                 host = qemu_get_ram_ptr(addr);
-            } else {
-                RAMBlock *block;
-                char name[64];
-
-                qemu_get_buffer(f, (uint8_t *)name, sizeof(name));
+            else
+                host = host_from_stream_offset(f, addr, flags);
 
-                QLIST_FOREACH(block, &ram.blocks, next) {
-                    if (!strncmp(name, block->name, sizeof(name)))
-                        break;
-                }
-                if (!block)
-                    return -EINVAL;
-
-                host = block->host + addr;
-            }
             ch = qemu_get_byte(f);
             memset(host, ch, TARGET_PAGE_SIZE);
 #ifndef _WIN32
@@ -365,23 +386,11 @@  int ram_load(QEMUFile *f, void *opaque, int version_id)
         } else if (flags & RAM_SAVE_FLAG_PAGE) {
             void *host;
 
-            if (version_id == 3) {
+            if (version_id == 3)
                 host = qemu_get_ram_ptr(addr);
-            } else {
-                RAMBlock *block;
-                char name[64];
+            else
+                host = host_from_stream_offset(f, addr, flags);
 
-                qemu_get_buffer(f, (uint8_t *)name, sizeof(name));
-
-                QLIST_FOREACH(block, &ram.blocks, next) {
-                    if (!strncmp(name, block->name, sizeof(name)))
-                        break;
-                }
-                if (!block)
-                    return -EINVAL;
-
-                host = block->host + addr;
-            }
             qemu_get_buffer(f, host, TARGET_PAGE_SIZE);
         }
         if (qemu_file_has_error(f)) {