#include <sys/mman.h>
#endif
#include "config.h"
-#include "monitor.h"
+#include "monitor/monitor.h"
#include "sysemu.h"
+#include "qemu/bitops.h"
+#include "qemu/bitmap.h"
#include "arch_init.h"
#include "audio/audio.h"
#include "hw/pc.h"
-#include "hw/pci.h"
+#include "hw/pci/pci.h"
#include "hw/audiodev.h"
#include "kvm.h"
-#include "migration.h"
-#include "net.h"
-#include "gdbstub.h"
+#include "migration/migration.h"
+#include "exec/gdbstub.h"
#include "hw/smbios.h"
-#include "exec-memory.h"
+#include "exec/address-spaces.h"
#include "hw/pcspk.h"
-#include "qemu/page_cache.h"
+#include "migration/page_cache.h"
+#include "qemu/config-file.h"
#include "qmp-commands.h"
+#include "trace.h"
#ifdef DEBUG_ARCH_INIT
#define DPRINTF(fmt, ...) \
static RAMBlock *last_block;
static ram_addr_t last_offset;
+static unsigned long *migration_bitmap;
+static uint64_t migration_dirty_pages;
static inline bool migration_bitmap_test_and_reset_dirty(MemoryRegion *mr,
ram_addr_t offset)
{
- bool ret = memory_region_get_dirty(mr, offset, TARGET_PAGE_SIZE,
- DIRTY_MEMORY_MIGRATION);
+ bool ret;
+ int nr = (mr->ram_addr + offset) >> TARGET_PAGE_BITS;
+
+ ret = test_and_clear_bit(nr, migration_bitmap);
if (ret) {
- memory_region_reset_dirty(mr, offset, TARGET_PAGE_SIZE,
- DIRTY_MEMORY_MIGRATION);
+ migration_dirty_pages--;
}
return ret;
}
-static inline void migration_bitmap_set_dirty(MemoryRegion *mr, int length)
+static inline bool migration_bitmap_set_dirty(MemoryRegion *mr,
+ ram_addr_t offset)
{
- ram_addr_t addr;
+ bool ret;
+ int nr = (mr->ram_addr + offset) >> TARGET_PAGE_BITS;
- for (addr = 0; addr < length; addr += TARGET_PAGE_SIZE) {
- if (!memory_region_get_dirty(mr, addr, TARGET_PAGE_SIZE,
- DIRTY_MEMORY_MIGRATION)) {
- memory_region_set_dirty(mr, addr, TARGET_PAGE_SIZE);
- }
+ ret = test_and_set_bit(nr, migration_bitmap);
+
+ if (!ret) {
+ migration_dirty_pages++;
}
+ return ret;
}
static void migration_bitmap_sync(void)
{
+ RAMBlock *block;
+ ram_addr_t addr;
+ uint64_t num_dirty_pages_init = migration_dirty_pages;
+ MigrationState *s = migrate_get_current();
+ static int64_t start_time;
+ static int64_t num_dirty_pages_period;
+ int64_t end_time;
+
+ if (!start_time) {
+ start_time = qemu_get_clock_ms(rt_clock);
+ }
+
+ trace_migration_bitmap_sync_start();
memory_global_sync_dirty_bitmap(get_system_memory());
+
+ QLIST_FOREACH(block, &ram_list.blocks, next) {
+ for (addr = 0; addr < block->length; addr += TARGET_PAGE_SIZE) {
+ if (memory_region_get_dirty(block->mr, addr, TARGET_PAGE_SIZE,
+ DIRTY_MEMORY_MIGRATION)) {
+ migration_bitmap_set_dirty(block->mr, addr);
+ }
+ }
+ memory_region_reset_dirty(block->mr, 0, block->length,
+ DIRTY_MEMORY_MIGRATION);
+ }
+ trace_migration_bitmap_sync_end(migration_dirty_pages
+ - num_dirty_pages_init);
+ num_dirty_pages_period += migration_dirty_pages - num_dirty_pages_init;
+ end_time = qemu_get_clock_ms(rt_clock);
+
+ /* more than 1 second = 1000 millisecons */
+ if (end_time > start_time + 1000) {
+ s->dirty_pages_rate = num_dirty_pages_period * 1000
+ / (end_time - start_time);
+ start_time = end_time;
+ num_dirty_pages_period = 0;
+ }
}
static ram_addr_t ram_save_remaining(void)
{
- return ram_list.dirty_pages;
+ return migration_dirty_pages;
}
uint64_t ram_bytes_remaining(void)
static int ram_save_setup(QEMUFile *f, void *opaque)
{
RAMBlock *block;
+ int64_t ram_pages = last_ram_offset() >> TARGET_PAGE_BITS;
+
+ migration_bitmap = bitmap_new(ram_pages);
+ bitmap_set(migration_bitmap, 0, ram_pages);
+ migration_dirty_pages = ram_pages;
bytes_transferred = 0;
reset_ram_globals();
acct_clear();
}
- /* Make sure all dirty bits are set */
- QLIST_FOREACH(block, &ram_list.blocks, next) {
- migration_bitmap_set_dirty(block->mr, block->length);
- }
-
memory_global_dirty_log_start();
- memory_global_sync_dirty_bitmap(get_system_memory());
+ migration_bitmap_sync();
qemu_put_be64(f, ram_bytes_total() | RAM_SAVE_FLAG_MEM_SIZE);
qemu_put_be64(f, RAM_SAVE_FLAG_EOS);
+ g_free(migration_bitmap);
+ migration_bitmap = NULL;
+
return 0;
}
memset(host, ch, TARGET_PAGE_SIZE);
#ifndef _WIN32
if (ch == 0 &&
- (!kvm_enabled() || kvm_has_sync_mmu())) {
+ (!kvm_enabled() || kvm_has_sync_mmu()) &&
+ getpagesize() <= TARGET_PAGE_SIZE) {
qemu_madvise(host, TARGET_PAGE_SIZE, QEMU_MADV_DONTNEED);
}
#endif