#include "qemu/bitmap.h"
#include "sysemu/arch_init.h"
#include "audio/audio.h"
-#include "hw/pc.h"
+#include "hw/i386/pc.h"
#include "hw/pci/pci.h"
-#include "hw/audiodev.h"
+#include "hw/audio/audio.h"
#include "sysemu/kvm.h"
#include "migration/migration.h"
-#include "exec/gdbstub.h"
-#include "hw/smbios.h"
+#include "hw/i386/smbios.h"
#include "exec/address-spaces.h"
-#include "hw/pcspk.h"
+#include "hw/audio/pcspk.h"
#include "migration/page_cache.h"
#include "qemu/config-file.h"
#include "qmp-commands.h"
#include "trace.h"
#include "exec/cpu-all.h"
+#include "hw/acpi/acpi.h"
#ifdef DEBUG_ARCH_INIT
#define DPRINTF(fmt, ...) \
#define QEMU_ARCH QEMU_ARCH_MICROBLAZE
#elif defined(TARGET_MIPS)
#define QEMU_ARCH QEMU_ARCH_MIPS
+#elif defined(TARGET_MOXIE)
+#define QEMU_ARCH QEMU_ARCH_MOXIE
#elif defined(TARGET_OPENRISC)
#define QEMU_ARCH QEMU_ARCH_OPENRISC
#elif defined(TARGET_PPC)
#define RAM_SAVE_FLAG_CONTINUE 0x20
#define RAM_SAVE_FLAG_XBZRLE 0x40
-#ifdef __ALTIVEC__
-#include <altivec.h>
-#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 <emmintrin.h>
-#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;
return ret;
}
}
-
+
return 0;
}
-static int is_dup_page(uint8_t *page)
+static inline bool is_zero_page(uint8_t *p)
{
- VECTYPE *p = (VECTYPE *)page;
- VECTYPE val = SPLAT(page);
- int i;
-
- for (i = 0; i < TARGET_PAGE_SIZE / sizeof(VECTYPE); i++) {
- if (!ALL_EQ(val, p[i])) {
- return 0;
- }
- }
-
- return 1;
+ return buffer_find_nonzero_offset(p, TARGET_PAGE_SIZE) ==
+ TARGET_PAGE_SIZE;
}
/* struct contains XBZRLE cache and a static page
/* 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;
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;
if (!cache_is_cached(XBZRLE.cache, current_addr)) {
if (!last_stage) {
- cache_insert(XBZRLE.cache, current_addr,
- g_memdup(current_data, TARGET_PAGE_SIZE));
+ cache_insert(XBZRLE.cache, current_addr, current_data);
}
acct_info.xbzrle_cache_miss++;
return -1;
static unsigned long *migration_bitmap;
static uint64_t migration_dirty_pages;
static uint32_t last_version;
+static bool ram_bulk_stage;
static inline
ram_addr_t migration_bitmap_find_and_reset_dirty(MemoryRegion *mr,
unsigned long nr = base + (start >> TARGET_PAGE_BITS);
unsigned long size = base + (int128_get64(mr->size) >> TARGET_PAGE_BITS);
- unsigned long next = find_next_bit(migration_bitmap, size, nr);
+ unsigned long next;
+
+ if (ram_bulk_stage && nr > base) {
+ next = nr + 1;
+ } else {
+ next = find_next_bit(migration_bitmap, size, nr);
+ }
if (next < size) {
clear_bit(next, migration_bitmap);
return ret;
}
+/* Needs iothread lock! */
+
static void migration_bitmap_sync(void)
{
RAMBlock *block;
if (end_time > start_time + 1000) {
s->dirty_pages_rate = num_dirty_pages_period * 1000
/ (end_time - start_time);
+ s->dirty_bytes_rate = s->dirty_pages_rate * TARGET_PAGE_SIZE;
start_time = end_time;
num_dirty_pages_period = 0;
}
/*
* ram_save_block: Writes a page of memory to the stream f
*
- * Returns: 0: if the page hasn't changed
- * -1: if there are no more dirty pages
- * n: the amount of bytes written in other case
+ * Returns: The number of bytes written.
+ * 0 means no dirty pages
*/
static int ram_save_block(QEMUFile *f, bool last_stage)
RAMBlock *block = last_seen_block;
ram_addr_t offset = last_offset;
bool complete_round = false;
- int bytes_sent = -1;
+ int bytes_sent = 0;
MemoryRegion *mr;
ram_addr_t current_addr;
if (!block) {
block = QTAILQ_FIRST(&ram_list.blocks);
complete_round = true;
+ ram_bulk_stage = false;
}
} else {
uint8_t *p;
p = memory_region_get_ram_ptr(mr) + offset;
- if (is_dup_page(p)) {
+ /* In doubt sent page as normal */
+ 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, *p);
- bytes_sent += 1;
- } else if (migrate_use_xbzrle()) {
+ 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 (!ram_bulk_stage && migrate_use_xbzrle()) {
current_addr = block->offset + offset;
bytes_sent = save_xbzrle_page(f, p, current_addr, block,
offset, cont, last_stage);
}
}
- /* either we didn't send yet (we may have had XBZRLE overflow) */
+ /* XBZRLE overflow or normal page */
if (bytes_sent == -1) {
bytes_sent = save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_PAGE);
- qemu_put_buffer(f, p, TARGET_PAGE_SIZE);
+ qemu_put_buffer_async(f, p, TARGET_PAGE_SIZE);
bytes_sent += TARGET_PAGE_SIZE;
acct_info.norm_pages++;
}
/* if page is unmodified, continue to the next */
- if (bytes_sent != 0) {
+ if (bytes_sent > 0) {
last_sent_block = block;
break;
}
last_sent_block = NULL;
last_offset = 0;
last_version = ram_list.version;
+ ram_bulk_stage = true;
}
#define MAX_WAIT 50 /* ms, half buffered_file limit */
bitmap_set(migration_bitmap, 0, ram_pages);
migration_dirty_pages = ram_pages;
- qemu_mutex_lock_ramlist();
- bytes_transferred = 0;
- reset_ram_globals();
-
if (migrate_use_xbzrle()) {
XBZRLE.cache = cache_init(migrate_xbzrle_cache_size() /
TARGET_PAGE_SIZE,
acct_clear();
}
+ qemu_mutex_lock_iothread();
+ qemu_mutex_lock_ramlist();
+ bytes_transferred = 0;
+ reset_ram_globals();
+
memory_global_dirty_log_start();
migration_bitmap_sync();
+ qemu_mutex_unlock_iothread();
qemu_put_be64(f, ram_bytes_total() | RAM_SAVE_FLAG_MEM_SIZE);
int ret;
int i;
int64_t t0;
+ int total_sent = 0;
qemu_mutex_lock_ramlist();
bytes_sent = ram_save_block(f, false);
/* no more blocks to sent */
- if (bytes_sent < 0) {
+ if (bytes_sent == 0) {
break;
}
- bytes_transferred += bytes_sent;
+ total_sent += bytes_sent;
acct_info.iterations++;
/* we want to check in the 1st loop, just in case it was the 1st time
and we had to sync the dirty bitmap.
i++;
}
+ qemu_mutex_unlock_ramlist();
+
if (ret < 0) {
+ bytes_transferred += total_sent;
return ret;
}
- qemu_mutex_unlock_ramlist();
qemu_put_be64(f, RAM_SAVE_FLAG_EOS);
+ total_sent += 8;
+ bytes_transferred += total_sent;
- return i;
+ return total_sent;
}
static int ram_save_complete(QEMUFile *f, void *opaque)
{
- migration_bitmap_sync();
-
qemu_mutex_lock_ramlist();
+ migration_bitmap_sync();
/* try transferring iterative blocks of memory */
bytes_sent = ram_save_block(f, true);
/* no more blocks to sent */
- if (bytes_sent < 0) {
+ if (bytes_sent == 0) {
break;
}
bytes_transferred += bytes_sent;
remaining_size = ram_save_remaining() * TARGET_PAGE_SIZE;
if (remaining_size < max_size) {
+ qemu_mutex_lock_iothread();
migration_bitmap_sync();
+ qemu_mutex_unlock_iothread();
remaining_size = ram_save_remaining() * TARGET_PAGE_SIZE;
}
return remaining_size;
qemu_get_buffer(f, host, TARGET_PAGE_SIZE);
} else if (flags & RAM_SAVE_FLAG_XBZRLE) {
- if (!migrate_use_xbzrle()) {
- return -EINVAL;
- }
void *host = host_from_stream_offset(f, addr, flags);
if (!host) {
return -EINVAL;
return 0;
}
-void do_acpitable_option(const char *optarg)
+void do_acpitable_option(const QemuOpts *opts)
{
#ifdef TARGET_I386
- if (acpi_table_add(optarg) < 0) {
- fprintf(stderr, "Wrong acpi table provided\n");
+ Error *err = NULL;
+
+ acpi_table_add(opts, &err);
+ if (err) {
+ fprintf(stderr, "Wrong acpi table provided: %s\n",
+ error_get_pretty(err));
+ error_free(err);
exit(1);
}
#endif