From 51d03b1696a5f38f5eaf24c900b5dddaf92181fe Mon Sep 17 00:00:00 2001 From: Juan Quintela <quintela@redhat.com> Date: Mon, 22 Nov 2010 15:57:08 -0200 Subject: [PATCH 4/6] Maintaing number of dirty pages RH-Author: Juan Quintela <quintela@redhat.com> Message-id: <45c762f4c255efddb7fdd905ae052af34f2c2d0f.1290441250.git.quintela@redhat.com> Patchwork-id: 13778 O-Subject: [PATCH 4/6] Maintaing number of dirty pages Bugzilla: 513765 589017 RH-Acked-by: Glauber Costa <glommer@redhat.com> RH-Acked-by: Jes Sorensen <Jes.Sorensen@redhat.com> RH-Acked-by: Alex Williamson <alex.williamson@redhat.com> Calculate the number of dirty pages takes a lot on hosts with lots of memory. Just maintain how many pages are dirty. Only sync bitmaps if number is small enough. Signed-off-by: Juan Quintela <quintela@redhat.com> --- qemu/cpu-all.h | 5 +++++ qemu/exec.c | 28 +++++++++++++++++++++++++++- qemu/vl.c | 29 +++++++++++++++++------------ 3 files changed, 49 insertions(+), 13 deletions(-) Signed-off-by: Eduardo Habkost <ehabkost@redhat.com> --- qemu/cpu-all.h | 5 +++++ qemu/exec.c | 28 +++++++++++++++++++++++++++- qemu/vl.c | 29 +++++++++++++++++------------ 3 files changed, 49 insertions(+), 13 deletions(-) diff --git a/qemu/cpu-all.h b/qemu/cpu-all.h index 4c3a669..14634c4 100644 --- a/qemu/cpu-all.h +++ b/qemu/cpu-all.h @@ -959,8 +959,13 @@ static inline int cpu_physical_memory_get_dirty(ram_addr_t addr, return phys_ram_dirty[addr >> TARGET_PAGE_BITS] & dirty_flags; } +extern uint64_t migration_dirty_pages; + static inline void cpu_physical_memory_set_dirty(ram_addr_t addr) { + if (!cpu_physical_memory_get_dirty(addr, MIGRATION_DIRTY_FLAG)) + migration_dirty_pages++; + phys_ram_dirty[addr >> TARGET_PAGE_BITS] = 0xff; } diff --git a/qemu/exec.c b/qemu/exec.c index 37bcc7a..2b621b4 100644 --- a/qemu/exec.c +++ b/qemu/exec.c @@ -1863,8 +1863,12 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end, #endif mask = ~dirty_flags; p = phys_ram_dirty + (start >> TARGET_PAGE_BITS); - for(i = 0; i < len; i++) + for(i = 0; i < len; i++) { + if (cpu_physical_memory_get_dirty(start + i * TARGET_PAGE_SIZE, + MIGRATION_DIRTY_FLAG & dirty_flags)) + migration_dirty_pages--; p[i] &= mask; + } if (kvm_enabled()) return; @@ -2512,6 +2516,9 @@ static void notdirty_mem_writeb(void *opaque, target_phys_addr_t ram_addr, kqemu_modify_page(cpu_single_env, ram_addr); #endif dirty_flags |= (0xff & ~CODE_DIRTY_FLAG); + if (!cpu_physical_memory_get_dirty(ram_addr, MIGRATION_DIRTY_FLAG)) + migration_dirty_pages++; + phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags; /* we remove the notdirty callback only if the code has been flushed */ @@ -2537,6 +2544,9 @@ static void notdirty_mem_writew(void *opaque, target_phys_addr_t ram_addr, kqemu_modify_page(cpu_single_env, ram_addr); #endif dirty_flags |= (0xff & ~CODE_DIRTY_FLAG); + if (!cpu_physical_memory_get_dirty(ram_addr, MIGRATION_DIRTY_FLAG)) + migration_dirty_pages++; + phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags; /* we remove the notdirty callback only if the code has been flushed */ @@ -2562,6 +2572,9 @@ static void notdirty_mem_writel(void *opaque, target_phys_addr_t ram_addr, kqemu_modify_page(cpu_single_env, ram_addr); #endif dirty_flags |= (0xff & ~CODE_DIRTY_FLAG); + if (!cpu_physical_memory_get_dirty(ram_addr, MIGRATION_DIRTY_FLAG)) + migration_dirty_pages++; + phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags; /* we remove the notdirty callback only if the code has been flushed */ @@ -2863,6 +2876,7 @@ static void io_mem_init(void) /* alloc dirty bits array */ phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS); memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS); + migration_dirty_pages = phys_ram_size >> TARGET_PAGE_BITS; } /* mem_read and mem_write are arrays of functions containing the @@ -3023,6 +3037,9 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, /* invalidate code */ tb_invalidate_phys_page_range(addr1, addr1 + l, 0); /* set dirty bit */ + if (!cpu_physical_memory_get_dirty(addr1, MIGRATION_DIRTY_FLAG)) + migration_dirty_pages++; + phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |= (0xff & ~CODE_DIRTY_FLAG); } @@ -3267,6 +3284,9 @@ void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val) /* invalidate code */ tb_invalidate_phys_page_range(addr1, addr1 + 4, 0); /* set dirty bit */ + if (!cpu_physical_memory_get_dirty(addr1, MIGRATION_DIRTY_FLAG)) + migration_dirty_pages++; + phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |= (0xff & ~CODE_DIRTY_FLAG); } @@ -3336,6 +3356,9 @@ void stl_phys(target_phys_addr_t addr, uint32_t val) /* invalidate code */ tb_invalidate_phys_page_range(addr1, addr1 + 4, 0); /* set dirty bit */ + if (!cpu_physical_memory_get_dirty(addr1, MIGRATION_DIRTY_FLAG)) + migration_dirty_pages++; + phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |= (0xff & ~CODE_DIRTY_FLAG); } @@ -3386,6 +3409,9 @@ void stw_phys_atomic(target_phys_addr_t addr, uint32_t val) /* invalidate code */ tb_invalidate_phys_page_range(addr1, addr1 + 2, 0); /* set dirty bit */ + if (!cpu_physical_memory_get_dirty(addr, MIGRATION_DIRTY_FLAG)) + migration_dirty_pages++; + phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |= (0xff & ~CODE_DIRTY_FLAG); } diff --git a/qemu/vl.c b/qemu/vl.c index 23fe8ff..409daa7 100644 --- a/qemu/vl.c +++ b/qemu/vl.c @@ -3385,6 +3385,8 @@ static int is_dup_page(uint8_t *page, uint8_t ch) return 1; } +uint64_t migration_dirty_pages; + static int ram_save_block(QEMUFile *f) { static ram_addr_t current_addr = 0; @@ -3432,15 +3434,7 @@ static uint64_t bytes_transferred = 0; static ram_addr_t ram_save_remaining(void) { - ram_addr_t addr; - ram_addr_t count = 0; - - for (addr = 0; addr < phys_ram_size; addr += TARGET_PAGE_SIZE) { - if (cpu_physical_memory_get_dirty(addr, MIGRATION_DIRTY_FLAG)) - count++; - } - - return count; + return migration_dirty_pages; } uint64_t ram_bytes_remaining(void) @@ -3516,9 +3510,20 @@ static int ram_save_live(QEMUFile *f, int stage, void *opaque) qemu_put_be64(f, RAM_SAVE_FLAG_EOS); - expected_time = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth; - - return (stage == 2) && (expected_time <= migrate_max_downtime()); + if (stage == 2) { + expected_time = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth; + if (expected_time <= migrate_max_downtime()) { + int r; + if (kvm_enabled() && (r = kvm_update_dirty_pages_log())) { + printf("%s: update dirty pages log failed %d\n", __FUNCTION__, r); + qemu_file_set_has_error(f); + return 0; + } + expected_time = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth; + return expected_time <= migrate_max_downtime(); + } + } + return 0; } static int ram_load_dead(QEMUFile *f, void *opaque) -- 1.7.3.2