From c44834c7d3f1996c7e2f80085580561bbbe31b83 Mon Sep 17 00:00:00 2001
From: Juan Quintela <quintela@redhat.com>
Date: Fri, 4 Feb 2011 12:20:02 -0200
Subject: [RHEL6 qemu-kvm PATCH 26/27] Maintaing number of dirty pages

RH-Author: Juan Quintela <quintela@redhat.com>
Message-id: <67252eb0e1a87c5de7337a6c0e0dfeea87104c39.1296800500.git.quintela@redhat.com>
Patchwork-id: 17740
O-Subject: [PATCH 7/8] Maintaing number of dirty pages
Bugzilla: 643970
RH-Acked-by: Alex Williamson <alex.williamson@redhat.com>
RH-Acked-by: Jes Sorensen <Jes.Sorensen@redhat.com>
RH-Acked-by: Amit Shah <amit.shah@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>
---
 cpu-all.h |    4 ++++
 exec.c    |   27 ++++++++++++++++++++++++++-
 vl.c      |   14 +-------------
 3 files changed, 31 insertions(+), 14 deletions(-)

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
 cpu-all.h |    4 ++++
 exec.c    |   27 ++++++++++++++++++++++++++-
 vl.c      |   14 +-------------
 3 files changed, 31 insertions(+), 14 deletions(-)

diff --git a/cpu-all.h b/cpu-all.h
index 854c63d..07ada32 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -862,6 +862,7 @@ typedef struct RAMBlock {
 
 typedef struct RAMList {
     uint8_t *phys_dirty;
+    uint64_t dirty_pages;
     QLIST_HEAD(ram, RAMBlock) blocks;
 } RAMList;
 extern RAMList ram_list;
@@ -905,6 +906,9 @@ static inline int cpu_physical_memory_get_dirty(ram_addr_t addr,
 
 static inline void cpu_physical_memory_set_dirty(ram_addr_t addr)
 {
+    if (!cpu_physical_memory_get_dirty(addr, MIGRATION_DIRTY_FLAG))
+        ram_list.dirty_pages++;
+
     ram_list.phys_dirty[addr >> TARGET_PAGE_BITS] = 0xff;
 }
 
diff --git a/exec.c b/exec.c
index d6c773d..b992016 100644
--- a/exec.c
+++ b/exec.c
@@ -1958,8 +1958,12 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
     len = length >> TARGET_PAGE_BITS;
     mask = ~dirty_flags;
     p = ram_list.phys_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))
+            ram_list.dirty_pages--;
         p[i] &= mask;
+    }
 
     if (kvm_enabled())
         return;
@@ -2752,6 +2756,8 @@ ram_addr_t qemu_ram_alloc(DeviceState *dev, const char *name, ram_addr_t size)
     memset(ram_list.phys_dirty + (new_block->offset >> TARGET_PAGE_BITS),
            0xff, size >> TARGET_PAGE_BITS);
 
+    ram_list.dirty_pages += size >> TARGET_PAGE_BITS;
+
     if (kvm_enabled())
         kvm_setup_guest_memory(new_block->host, size);
 
@@ -2930,6 +2936,9 @@ static void notdirty_mem_writeb(void *opaque, target_phys_addr_t ram_addr,
     }
     stb_p(qemu_get_ram_ptr(ram_addr), val);
     dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
+    if (!cpu_physical_memory_get_dirty(ram_addr,
+                                      MIGRATION_DIRTY_FLAG & dirty_flags))
+        ram_list.dirty_pages++;
     ram_list.phys_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
     /* we remove the notdirty callback only if the code has been
        flushed */
@@ -2950,6 +2959,9 @@ static void notdirty_mem_writew(void *opaque, target_phys_addr_t ram_addr,
     }
     stw_p(qemu_get_ram_ptr(ram_addr), val);
     dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
+    if (!cpu_physical_memory_get_dirty(ram_addr,
+                                      MIGRATION_DIRTY_FLAG & dirty_flags))
+        ram_list.dirty_pages++;
     ram_list.phys_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
     /* we remove the notdirty callback only if the code has been
        flushed */
@@ -2970,6 +2982,9 @@ static void notdirty_mem_writel(void *opaque, target_phys_addr_t ram_addr,
     }
     stl_p(qemu_get_ram_ptr(ram_addr), val);
     dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
+    if (!cpu_physical_memory_get_dirty(ram_addr,
+                                      MIGRATION_DIRTY_FLAG & dirty_flags))
+        ram_list.dirty_pages++;
     ram_list.phys_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
     /* we remove the notdirty callback only if the code has been
        flushed */
@@ -3424,6 +3439,8 @@ 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))
+                        ram_list.dirty_pages++;
                     ram_list.phys_dirty[addr1 >> TARGET_PAGE_BITS] |=
                         (0xff & ~CODE_DIRTY_FLAG);
                 }
@@ -3638,6 +3655,8 @@ void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
                     /* invalidate code */
                     tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
                     /* set dirty bit */
+                    if (!cpu_physical_memory_get_dirty(addr1, MIGRATION_DIRTY_FLAG))
+                        ram_list.dirty_pages++;
                     ram_list.phys_dirty[addr1 >> TARGET_PAGE_BITS] |=
                         (0xff & ~CODE_DIRTY_FLAG);
                 }
@@ -3799,6 +3818,8 @@ 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))
+                        ram_list.dirty_pages++;
                 ram_list.phys_dirty[addr1 >> TARGET_PAGE_BITS] |=
                     (0xff & ~CODE_DIRTY_FLAG);
             }
@@ -3868,6 +3889,8 @@ 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))
+                ram_list.dirty_pages++;
             ram_list.phys_dirty[addr1 >> TARGET_PAGE_BITS] |=
                 (0xff & ~CODE_DIRTY_FLAG);
         }
@@ -3911,6 +3934,8 @@ void stw_phys(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(addr1, MIGRATION_DIRTY_FLAG))
+                ram_list.dirty_pages++;
             ram_list.phys_dirty[addr1 >> TARGET_PAGE_BITS] |=
                 (0xff & ~CODE_DIRTY_FLAG);
         }
diff --git a/vl.c b/vl.c
index 733139c..d899c9c 100644
--- a/vl.c
+++ b/vl.c
@@ -3306,19 +3306,7 @@ static uint64_t bytes_transferred;
 
 static ram_addr_t ram_save_remaining(void)
 {
-    RAMBlock *block;
-    ram_addr_t count = 0;
-
-    QLIST_FOREACH(block, &ram_list.blocks, next) {
-        ram_addr_t addr;
-        for (addr = block->offset; addr < block->offset + block->length;
-             addr += TARGET_PAGE_SIZE) {
-            if (cpu_physical_memory_get_dirty(addr, MIGRATION_DIRTY_FLAG))
-                count++;
-        }
-    }
-
-    return count;
+    return ram_list.dirty_pages;
 }
 
 uint64_t ram_bytes_remaining(void)
-- 
1.7.3.2

