From e344b8a16de429ada3d9126f26e2a96d71348356 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 12 Mar 2013 14:06:00 +1100 Subject: savevm: Add VMSTATE_UINT64_EQUAL helpers The savevm code already includes a number of *_EQUAL helpers which act as sanity checks verifying that the configuration of the saved state matches that of the machine we're loading into to work. Variants already exist for 8 bit 16 bit and 32 bit integers, but not 64 bit integers. This patch fills that hole, adding a UINT64 version. Signed-off-by: David Gibson Signed-off-by: Juan Quintela --- include/migration/vmstate.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'include') diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index 6666d27b25..f12ad79aba 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -149,6 +149,7 @@ extern const VMStateInfo vmstate_info_uint8_equal; extern const VMStateInfo vmstate_info_uint16_equal; extern const VMStateInfo vmstate_info_int32_equal; extern const VMStateInfo vmstate_info_uint32_equal; +extern const VMStateInfo vmstate_info_uint64_equal; extern const VMStateInfo vmstate_info_int32_le; extern const VMStateInfo vmstate_info_uint8; @@ -521,6 +522,12 @@ extern const VMStateInfo vmstate_info_bitmap; #define VMSTATE_UINT32_EQUAL(_f, _s) \ VMSTATE_SINGLE(_f, _s, 0, vmstate_info_uint32_equal, uint32_t) +#define VMSTATE_UINT64_EQUAL_V(_f, _s, _v) \ + VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint64_equal, uint64_t) + +#define VMSTATE_UINT64_EQUAL(_f, _s) \ + VMSTATE_UINT64_EQUAL_V(_f, _s, 0) + #define VMSTATE_INT32_LE(_f, _s) \ VMSTATE_SINGLE(_f, _s, 0, vmstate_info_int32_le, int32_t) -- cgit v1.2.3-55-g7522 From d58f5598342ffebe6c6278d8b90792060fca4792 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 12 Mar 2013 14:06:01 +1100 Subject: savevm: Add VMSTATE_UINTTL_EQUAL helper This adds an _EQUAL VMSTATE helper for target_ulongs, defined in terms of VMSTATE_UINT32_EQUAL or VMSTATE_UINT64_EQUAL as appropriate. Signed-off-by: David Gibson Signed-off-by: Juan Quintela --- hw/hw.h | 6 ++++++ include/migration/vmstate.h | 7 +++++-- 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/hw/hw.h b/hw/hw.h index 1553e54aa7..1fb9afa322 100644 --- a/hw/hw.h +++ b/hw/hw.h @@ -52,16 +52,22 @@ int qemu_boot_set(const char *boot_devices); #if TARGET_LONG_BITS == 64 #define VMSTATE_UINTTL_V(_f, _s, _v) \ VMSTATE_UINT64_V(_f, _s, _v) +#define VMSTATE_UINTTL_EQUAL_V(_f, _s, _v) \ + VMSTATE_UINT64_EQUAL_V(_f, _s, _v) #define VMSTATE_UINTTL_ARRAY_V(_f, _s, _n, _v) \ VMSTATE_UINT64_ARRAY_V(_f, _s, _n, _v) #else #define VMSTATE_UINTTL_V(_f, _s, _v) \ VMSTATE_UINT32_V(_f, _s, _v) +#define VMSTATE_UINTTL_EQUAL_V(_f, _s, _v) \ + VMSTATE_UINT32_EQUAL_V(_f, _s, _v) #define VMSTATE_UINTTL_ARRAY_V(_f, _s, _n, _v) \ VMSTATE_UINT32_ARRAY_V(_f, _s, _n, _v) #endif #define VMSTATE_UINTTL(_f, _s) \ VMSTATE_UINTTL_V(_f, _s, 0) +#define VMSTATE_UINTTL_EQUAL(_f, _s) \ + VMSTATE_UINTTL_EQUAL_V(_f, _s, 0) #define VMSTATE_UINTTL_ARRAY(_f, _s, _n) \ VMSTATE_UINTTL_ARRAY_V(_f, _s, _n, 0) diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index f12ad79aba..294d455b7b 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -519,8 +519,11 @@ extern const VMStateInfo vmstate_info_bitmap; #define VMSTATE_INT32_EQUAL(_f, _s) \ VMSTATE_SINGLE(_f, _s, 0, vmstate_info_int32_equal, int32_t) -#define VMSTATE_UINT32_EQUAL(_f, _s) \ - VMSTATE_SINGLE(_f, _s, 0, vmstate_info_uint32_equal, uint32_t) +#define VMSTATE_UINT32_EQUAL_V(_f, _s, _v) \ + VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint32_equal, uint32_t) + +#define VMSTATE_UINT32_EQUAL(_f, _s) \ + VMSTATE_UINT32_EQUAL_V(_f, _s, 0) #define VMSTATE_UINT64_EQUAL_V(_f, _s, _v) \ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint64_equal, uint64_t) -- cgit v1.2.3-55-g7522 From 213945e4d753b5f214468ff746d65fa76e21dbd1 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 12 Mar 2013 14:06:02 +1100 Subject: savevm: Add VMSTATE_FLOAT64 helpers The current savevm code includes VMSTATE helpers for a number of commonly used data types, but not for the float64 type used by the internal floating point emulation code. This patch fixes the deficiency. Signed-off-by: David Gibson Signed-off-by: Juan Quintela --- include/migration/vmstate.h | 15 +++++++++++++++ savevm.c | 23 +++++++++++++++++++++++ 2 files changed, 38 insertions(+) (limited to 'include') diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index 294d455b7b..5c31ff1c9b 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -157,6 +157,8 @@ extern const VMStateInfo vmstate_info_uint16; extern const VMStateInfo vmstate_info_uint32; extern const VMStateInfo vmstate_info_uint64; +extern const VMStateInfo vmstate_info_float64; + extern const VMStateInfo vmstate_info_timer; extern const VMStateInfo vmstate_info_buffer; extern const VMStateInfo vmstate_info_unused_buffer; @@ -543,6 +545,13 @@ extern const VMStateInfo vmstate_info_bitmap; #define VMSTATE_UINT32_TEST(_f, _s, _t) \ VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint32, uint32_t) + +#define VMSTATE_FLOAT64_V(_f, _s, _v) \ + VMSTATE_SINGLE(_f, _s, _v, vmstate_info_float64, float64) + +#define VMSTATE_FLOAT64(_f, _s) \ + VMSTATE_FLOAT64_V(_f, _s, 0) + #define VMSTATE_TIMER_TEST(_f, _s, _test) \ VMSTATE_POINTER_TEST(_f, _s, _test, vmstate_info_timer, QEMUTimer *) @@ -609,6 +618,12 @@ extern const VMStateInfo vmstate_info_bitmap; #define VMSTATE_INT64_ARRAY(_f, _s, _n) \ VMSTATE_INT64_ARRAY_V(_f, _s, _n, 0) +#define VMSTATE_FLOAT64_ARRAY_V(_f, _s, _n, _v) \ + VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_float64, float64) + +#define VMSTATE_FLOAT64_ARRAY(_f, _s, _n) \ + VMSTATE_FLOAT64_ARRAY_V(_f, _s, _n, 0) + #define VMSTATE_BUFFER_V(_f, _s, _v) \ VMSTATE_STATIC_BUFFER(_f, _s, _v, NULL, 0, sizeof(typeof_field(_s, _f))) diff --git a/savevm.c b/savevm.c index cd98b0db1d..8f1344a959 100644 --- a/savevm.c +++ b/savevm.c @@ -1133,6 +1133,29 @@ const VMStateInfo vmstate_info_uint16_equal = { .put = put_uint16, }; +/* floating point */ + +static int get_float64(QEMUFile *f, void *pv, size_t size) +{ + float64 *v = pv; + + *v = make_float64(qemu_get_be64(f)); + return 0; +} + +static void put_float64(QEMUFile *f, void *pv, size_t size) +{ + uint64_t *v = pv; + + qemu_put_be64(f, float64_val(*v)); +} + +const VMStateInfo vmstate_info_float64 = { + .name = "float64", + .get = get_float64, + .put = put_float64, +}; + /* timers */ static int get_timer(QEMUFile *f, void *pv, size_t size) -- cgit v1.2.3-55-g7522 From 8474a9dd6757be064bf4b35f422b4640d1cca0a5 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 12 Mar 2013 14:06:03 +1100 Subject: savevm: Add VMSTATE_STRUCT_VARRAY_POINTER_UINT32 Currently the savevm code contains a VMSTATE_STRUCT_VARRAY_POINTER_INT32 helper (a variably sized array with the number of elements in an int32_t), but not VMSTATE_STRUCT_VARRAY_POINTER_UINT32 (... with the number of elements in a uint32_t). This patch (trivially) fixes the deficiency. Signed-off-by: David Gibson Signed-off-by: Juan Quintela --- include/migration/vmstate.h | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'include') diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index 5c31ff1c9b..d8af9f2cb3 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -343,6 +343,16 @@ extern const VMStateInfo vmstate_info_bitmap; .offset = vmstate_offset_pointer(_state, _field, _type), \ } +#define VMSTATE_STRUCT_VARRAY_POINTER_UINT32(_field, _state, _field_num, _vmsd, _type) { \ + .name = (stringify(_field)), \ + .version_id = 0, \ + .num_offset = vmstate_offset_value(_state, _field_num, uint32_t),\ + .size = sizeof(_type), \ + .vmsd = &(_vmsd), \ + .flags = VMS_POINTER | VMS_VARRAY_INT32 | VMS_STRUCT, \ + .offset = vmstate_offset_pointer(_state, _field, _type), \ +} + #define VMSTATE_STRUCT_VARRAY_POINTER_UINT16(_field, _state, _field_num, _vmsd, _type) { \ .name = (stringify(_field)), \ .version_id = 0, \ -- cgit v1.2.3-55-g7522 From 377e2cb96b76c2b0023c1acc7230bf3a9e9f9f40 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 12 Mar 2013 14:06:04 +1100 Subject: savevm: Fix bugs in the VMSTATE_VBUFFER_MULTIPLY definition The VMSTATE_BUFFER_MULTIPLY macro is misnamed - it actually specifies a variably sized buffer with VMS_VBUFFER, so should be named VMSTATE_VBUFFER_MULTIPLY. This patch fixes this (the macro had no current users under either name). In addition, unlike the other VMSTATE_VBUFFER variants, this macro did not specify VMS_POINTER. This patch fixes this bug as well. Signed-off-by: David Gibson Signed-off-by: Juan Quintela --- include/migration/vmstate.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index d8af9f2cb3..65918a9abe 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -393,14 +393,14 @@ extern const VMStateInfo vmstate_info_bitmap; .offset = vmstate_offset_buffer(_state, _field) + _start, \ } -#define VMSTATE_BUFFER_MULTIPLY(_field, _state, _version, _test, _start, _field_size, _multiply) { \ +#define VMSTATE_VBUFFER_MULTIPLY(_field, _state, _version, _test, _start, _field_size, _multiply) { \ .name = (stringify(_field)), \ .version_id = (_version), \ .field_exists = (_test), \ .size_offset = vmstate_offset_value(_state, _field_size, uint32_t),\ .size = (_multiply), \ .info = &vmstate_info_buffer, \ - .flags = VMS_VBUFFER|VMS_MULTIPLY, \ + .flags = VMS_VBUFFER|VMS_POINTER|VMS_MULTIPLY, \ .offset = offsetof(_state, _field), \ .start = (_start), \ } -- cgit v1.2.3-55-g7522 From c61ca00ada744eb24825be2ba4d6ba8fe3a870a4 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Tue, 26 Mar 2013 10:58:30 +0100 Subject: move vector definitions to qemu-common.h vector optimizations will now be used at various places not just in is_dup_page() in arch_init.c Signed-off-by: Peter Lieven Signed-off-by: Juan Quintela --- arch_init.c | 20 -------------------- include/qemu-common.h | 21 +++++++++++++++++++++ 2 files changed, 21 insertions(+), 20 deletions(-) (limited to 'include') diff --git a/arch_init.c b/arch_init.c index e8ade9e639..35974c2828 100644 --- a/arch_init.c +++ b/arch_init.c @@ -116,26 +116,6 @@ const uint32_t arch_type = QEMU_ARCH; #define RAM_SAVE_FLAG_CONTINUE 0x20 #define RAM_SAVE_FLAG_XBZRLE 0x40 -#ifdef __ALTIVEC__ -#include -#define VECTYPE vector unsigned char -#define SPLAT(p) vec_splat(vec_ld(0, p), 0) -#define ALL_EQ(v1, v2) vec_all_eq(v1, v2) -/* altivec.h may redefine the bool macro as vector type. - * Reset it to POSIX semantics. */ -#undef bool -#define bool _Bool -#elif defined __SSE2__ -#include -#define VECTYPE __m128i -#define SPLAT(p) _mm_set1_epi8(*(p)) -#define ALL_EQ(v1, v2) (_mm_movemask_epi8(_mm_cmpeq_epi8(v1, v2)) == 0xFFFF) -#else -#define VECTYPE unsigned long -#define SPLAT(p) (*(p) * (~0UL / 255)) -#define ALL_EQ(v1, v2) ((v1) == (v2)) -#endif - static struct defconfig_file { const char *filename; diff --git a/include/qemu-common.h b/include/qemu-common.h index 2371132c11..d7ad3a70f1 100644 --- a/include/qemu-common.h +++ b/include/qemu-common.h @@ -448,4 +448,25 @@ int uleb128_decode_small(const uint8_t *in, uint32_t *n); void hexdump(const char *buf, FILE *fp, const char *prefix, size_t size); +/* vector definitions */ +#ifdef __ALTIVEC__ +#include +#define VECTYPE vector unsigned char +#define SPLAT(p) vec_splat(vec_ld(0, p), 0) +#define ALL_EQ(v1, v2) vec_all_eq(v1, v2) +/* altivec.h may redefine the bool macro as vector type. + * Reset it to POSIX semantics. */ +#undef bool +#define bool _Bool +#elif defined __SSE2__ +#include +#define VECTYPE __m128i +#define SPLAT(p) _mm_set1_epi8(*(p)) +#define ALL_EQ(v1, v2) (_mm_movemask_epi8(_mm_cmpeq_epi8(v1, v2)) == 0xFFFF) +#else +#define VECTYPE unsigned long +#define SPLAT(p) (*(p) * (~0UL / 255)) +#define ALL_EQ(v1, v2) ((v1) == (v2)) +#endif + #endif -- cgit v1.2.3-55-g7522 From 41a259bd2b1796ddabdae600ee539269a7ddb6a5 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Tue, 26 Mar 2013 10:58:32 +0100 Subject: cutils: add a function to find non-zero content in a buffer this adds buffer_find_nonzero_offset() which is a SSE2/Altivec optimized function that searches for non-zero content in a buffer. the function starts full unrolling only after the first few chunks have been checked one by one. analyzing real memory page data has revealed that non-zero pages are non-zero within the first 256-512 bits in most cases. as this function is also heavily used to check for zero memory pages this tweak has been made to avoid the high setup costs of the fully unrolled check for non-zero pages. due to the optimizations used in the function there are restrictions on buffer address and search length. the function can_use_buffer_find_nonzero_content() can be used to check if the function can be used safely. Signed-off-by: Peter Lieven Signed-off-by: Juan Quintela --- include/qemu-common.h | 10 ++++++++++ util/cutils.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) (limited to 'include') diff --git a/include/qemu-common.h b/include/qemu-common.h index d7ad3a70f1..31fff22f32 100644 --- a/include/qemu-common.h +++ b/include/qemu-common.h @@ -469,4 +469,14 @@ void hexdump(const char *buf, FILE *fp, const char *prefix, size_t size); #define ALL_EQ(v1, v2) ((v1) == (v2)) #endif +#define BUFFER_FIND_NONZERO_OFFSET_UNROLL_FACTOR 8 +static inline bool +can_use_buffer_find_nonzero_offset(const void *buf, size_t len) +{ + return (len % (BUFFER_FIND_NONZERO_OFFSET_UNROLL_FACTOR + * sizeof(VECTYPE)) == 0 + && ((uintptr_t) buf) % sizeof(VECTYPE) == 0); +} +size_t buffer_find_nonzero_offset(const void *buf, size_t len); + #endif diff --git a/util/cutils.c b/util/cutils.c index 1439da4f99..0696a3ba5e 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -142,6 +142,61 @@ int qemu_fdatasync(int fd) #endif } +/* + * Searches for an area with non-zero content in a buffer + * + * Attention! The len must be a multiple of + * BUFFER_FIND_NONZERO_OFFSET_UNROLL_FACTOR * sizeof(VECTYPE) + * and addr must be a multiple of sizeof(VECTYPE) due to + * restriction of optimizations in this function. + * + * can_use_buffer_find_nonzero_offset() can be used to check + * these requirements. + * + * The return value is the offset of the non-zero area rounded + * down to a multiple of sizeof(VECTYPE) for the first + * BUFFER_FIND_NONZERO_OFFSET_UNROLL_FACTOR chunks and down to + * BUFFER_FIND_NONZERO_OFFSET_UNROLL_FACTOR * sizeof(VECTYPE) + * afterwards. + * + * If the buffer is all zero the return value is equal to len. + */ + +size_t buffer_find_nonzero_offset(const void *buf, size_t len) +{ + const VECTYPE *p = buf; + const VECTYPE zero = (VECTYPE){0}; + size_t i; + + assert(can_use_buffer_find_nonzero_offset(buf, len)); + + if (!len) { + return 0; + } + + for (i = 0; i < BUFFER_FIND_NONZERO_OFFSET_UNROLL_FACTOR; i++) { + if (!ALL_EQ(p[i], zero)) { + return i * sizeof(VECTYPE); + } + } + + for (i = BUFFER_FIND_NONZERO_OFFSET_UNROLL_FACTOR; + i < len / sizeof(VECTYPE); + i += BUFFER_FIND_NONZERO_OFFSET_UNROLL_FACTOR) { + VECTYPE tmp0 = p[i + 0] | p[i + 1]; + VECTYPE tmp1 = p[i + 2] | p[i + 3]; + VECTYPE tmp2 = p[i + 4] | p[i + 5]; + VECTYPE tmp3 = p[i + 6] | p[i + 7]; + VECTYPE tmp01 = tmp0 | tmp1; + VECTYPE tmp23 = tmp2 | tmp3; + if (!ALL_EQ(tmp01 | tmp23, zero)) { + break; + } + } + + return i * sizeof(VECTYPE); +} + /* * Checks if a buffer is all zeroes * -- cgit v1.2.3-55-g7522 From f1c72795af573b24a7da5eb52375c9aba8a37972 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Tue, 26 Mar 2013 10:58:37 +0100 Subject: migration: do not sent zero pages in bulk stage during bulk stage of ram migration if a page is a zero page do not send it at all. the memory at the destination reads as zero anyway. even if there is an madvise with QEMU_MADV_DONTNEED at the target upon receipt of a zero page I have observed that the target starts swapping if the memory is overcommitted. it seems that the pages are dropped asynchronously. this patch also updates QMP to return the number of skipped pages in MigrationStats. Signed-off-by: Peter Lieven Reviewed-by: Eric Blake Signed-off-by: Juan Quintela --- arch_init.c | 24 ++++++++++++++++++++---- hmp.c | 2 ++ include/migration/migration.h | 2 ++ migration.c | 3 ++- qapi-schema.json | 8 +++++--- qmp-commands.hx | 1 + 6 files changed, 32 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/arch_init.c b/arch_init.c index 1291bd2b3a..3a0d02eafa 100644 --- a/arch_init.c +++ b/arch_init.c @@ -183,6 +183,7 @@ int64_t xbzrle_cache_resize(int64_t new_size) /* accounting for migration statistics */ typedef struct AccountingInfo { uint64_t dup_pages; + uint64_t skipped_pages; uint64_t norm_pages; uint64_t iterations; uint64_t xbzrle_bytes; @@ -208,6 +209,16 @@ uint64_t dup_mig_pages_transferred(void) return acct_info.dup_pages; } +uint64_t skipped_mig_bytes_transferred(void) +{ + return acct_info.skipped_pages * TARGET_PAGE_SIZE; +} + +uint64_t skipped_mig_pages_transferred(void) +{ + return acct_info.skipped_pages; +} + uint64_t norm_mig_bytes_transferred(void) { return acct_info.norm_pages * TARGET_PAGE_SIZE; @@ -440,10 +451,15 @@ static int ram_save_block(QEMUFile *f, bool last_stage) bytes_sent = -1; if (is_zero_page(p)) { acct_info.dup_pages++; - bytes_sent = save_block_hdr(f, block, offset, cont, - RAM_SAVE_FLAG_COMPRESS); - qemu_put_byte(f, 0); - bytes_sent++; + if (!ram_bulk_stage) { + bytes_sent = save_block_hdr(f, block, offset, cont, + RAM_SAVE_FLAG_COMPRESS); + qemu_put_byte(f, 0); + bytes_sent++; + } else { + acct_info.skipped_pages++; + bytes_sent = 0; + } } else if (migrate_use_xbzrle()) { current_addr = block->offset + offset; bytes_sent = save_xbzrle_page(f, p, current_addr, block, diff --git a/hmp.c b/hmp.c index b0a861cfbb..e3e833edf4 100644 --- a/hmp.c +++ b/hmp.c @@ -173,6 +173,8 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict) info->ram->total >> 10); monitor_printf(mon, "duplicate: %" PRIu64 " pages\n", info->ram->duplicate); + monitor_printf(mon, "skipped: %" PRIu64 " pages\n", + info->ram->skipped); monitor_printf(mon, "normal: %" PRIu64 " pages\n", info->ram->normal); monitor_printf(mon, "normal bytes: %" PRIu64 " kbytes\n", diff --git a/include/migration/migration.h b/include/migration/migration.h index bb617fdacf..e2acec64c0 100644 --- a/include/migration/migration.h +++ b/include/migration/migration.h @@ -96,6 +96,8 @@ extern SaveVMHandlers savevm_ram_handlers; uint64_t dup_mig_bytes_transferred(void); uint64_t dup_mig_pages_transferred(void); +uint64_t skipped_mig_bytes_transferred(void); +uint64_t skipped_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); diff --git a/migration.c b/migration.c index 185d11260d..7fb2147391 100644 --- a/migration.c +++ b/migration.c @@ -197,11 +197,11 @@ MigrationInfo *qmp_query_migrate(Error **errp) info->ram->remaining = ram_bytes_remaining(); info->ram->total = ram_bytes_total(); info->ram->duplicate = dup_mig_pages_transferred(); + info->ram->skipped = skipped_mig_pages_transferred(); info->ram->normal = norm_mig_pages_transferred(); info->ram->normal_bytes = norm_mig_bytes_transferred(); info->ram->dirty_pages_rate = s->dirty_pages_rate; - if (blk_mig_active()) { info->has_disk = true; info->disk = g_malloc0(sizeof(*info->disk)); @@ -227,6 +227,7 @@ MigrationInfo *qmp_query_migrate(Error **errp) info->ram->remaining = 0; info->ram->total = ram_bytes_total(); info->ram->duplicate = dup_mig_pages_transferred(); + info->ram->skipped = skipped_mig_pages_transferred(); info->ram->normal = norm_mig_pages_transferred(); info->ram->normal_bytes = norm_mig_bytes_transferred(); break; diff --git a/qapi-schema.json b/qapi-schema.json index 088f4e150f..6c4966be43 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -496,7 +496,9 @@ # # @total: total amount of bytes involved in the migration process # -# @duplicate: number of duplicate pages (since 1.2) +# @duplicate: number of duplicate (zero) pages (since 1.2) +# +# @skipped: number of skipped zero pages (since 1.5) # # @normal : number of normal pages (since 1.2) # @@ -509,8 +511,8 @@ ## { 'type': 'MigrationStats', 'data': {'transferred': 'int', 'remaining': 'int', 'total': 'int' , - 'duplicate': 'int', 'normal': 'int', 'normal-bytes': 'int', - 'dirty-pages-rate' : 'int' } } + 'duplicate': 'int', 'skipped': 'int', 'normal': 'int', + 'normal-bytes': 'int', 'dirty-pages-rate' : 'int' } } ## # @XBZRLECacheStats diff --git a/qmp-commands.hx b/qmp-commands.hx index 5e847b18d9..fdc40486f6 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -2445,6 +2445,7 @@ The main json-object contains the following: - "duplicate": number of pages filled entirely with the same byte (json-int) These are sent over the wire much more efficiently. + - "skipped": number of skipped zero pages (json-int) - "normal" : number of whole pages transfered. I.e. they were not sent as duplicate or xbzrle pages (json-int) - "normal-bytes" : number of bytes transferred in whole -- cgit v1.2.3-55-g7522 From d913829f0fd8451abcb1fd9d6dfce5586d9d7e10 Mon Sep 17 00:00:00 2001 From: Orit Wasserman Date: Fri, 22 Mar 2013 16:47:57 +0200 Subject: Add QemuFileWritevBuffer QemuFileOps This will allow us to write an iovec Signed-off-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- include/migration/qemu-file.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'include') diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h index df812617f8..8b8070fbbf 100644 --- a/include/migration/qemu-file.h +++ b/include/migration/qemu-file.h @@ -51,11 +51,18 @@ typedef int (QEMUFileCloseFunc)(void *opaque); */ typedef int (QEMUFileGetFD)(void *opaque); +/* + * This function writes an iovec to file. + */ +typedef ssize_t (QEMUFileWritevBufferFunc)(void *opaque, struct iovec *iov, + int iovcnt); + typedef struct QEMUFileOps { QEMUFilePutBufferFunc *put_buffer; QEMUFileGetBufferFunc *get_buffer; QEMUFileCloseFunc *close; QEMUFileGetFD *get_fd; + QEMUFileWritevBufferFunc *writev_buffer; } QEMUFileOps; QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops); -- cgit v1.2.3-55-g7522 From 6181ec245529e0d40ac669fe3044eef3a9e19610 Mon Sep 17 00:00:00 2001 From: Orit Wasserman Date: Fri, 22 Mar 2013 16:48:02 +0200 Subject: Add qemu_put_buffer_async This allows us to add a buffer to the iovec to send without copying it into the static buffer, the buffer will be sent later when qemu_fflush is called. Signed-off-by: Orit Wasserman Signed-off-by: Juan Quintela --- include/migration/qemu-file.h | 5 +++++ savevm.c | 34 ++++++++++++++++++++++++++-------- 2 files changed, 31 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h index 8b8070fbbf..623c434b15 100644 --- a/include/migration/qemu-file.h +++ b/include/migration/qemu-file.h @@ -75,6 +75,11 @@ int qemu_fclose(QEMUFile *f); int64_t qemu_ftell(QEMUFile *f); void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size); void qemu_put_byte(QEMUFile *f, int v); +/* + * put_buffer without copying the buffer. + * The buffer should be available till it is sent asynchronously. + */ +void qemu_put_buffer_async(QEMUFile *f, const uint8_t *buf, int size); static inline void qemu_put_ubyte(QEMUFile *f, unsigned int v) { diff --git a/savevm.c b/savevm.c index 1d929878ae..406caa90e5 100644 --- a/savevm.c +++ b/savevm.c @@ -633,6 +633,28 @@ static void add_to_iovec(QEMUFile *f, const uint8_t *buf, int size) } } +void qemu_put_buffer_async(QEMUFile *f, const uint8_t *buf, int size) +{ + if (f->last_error) { + return; + } + + if (f->is_write == 0 && f->buf_index > 0) { + fprintf(stderr, + "Attempted to write to buffer while read buffer is not empty\n"); + abort(); + } + + add_to_iovec(f, buf, size); + + f->is_write = 1; + f->bytes_xfer += size; + + if (f->buf_index >= IO_BUF_SIZE || f->iovcnt >= MAX_IOV_SIZE) { + qemu_fflush(f); + } +} + void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size) { int l; @@ -652,18 +674,14 @@ void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size) if (l > size) l = size; memcpy(f->buf + f->buf_index, buf, l); - add_to_iovec(f, f->buf + f->buf_index, l); f->is_write = 1; f->buf_index += l; - f->bytes_xfer += l; + qemu_put_buffer_async(f, f->buf + (f->buf_index - l), l); + if (qemu_file_get_error(f)) { + break; + } buf += l; size -= l; - if (f->buf_index >= IO_BUF_SIZE || f->iovcnt >= MAX_IOV_SIZE) { - qemu_fflush(f); - if (qemu_file_get_error(f)) { - break; - } - } } } -- cgit v1.2.3-55-g7522