[RFC PATCH v2 3/3] Per memslot dirty bitmap

Umesh Deshpande
2011-07-29T20:57:34Z

This patch creates a separate dirty bitmap for each slot. Currently dirty bitmap
is created for addresses ranging from 0 to the end address of the last memory
slot. Since the memslots are not necessarily contiguous, current bitmap might
contain empty region or holes that doesn't represent any VM pages. This patch
reduces the size of the dirty bitmap by allocating per memslot dirty bitmaps.

Signed-off-by: Umesh Deshpande <udeshpan@redhat.com>
---
cpu-all.h | 40 +++++++++++++++++++++++++++++++++-------
exec.c | 38 +++++++++++++++++++++++---------------
xen-all.c | 6 ++----
3 files changed, 58 insertions(+), 26 deletions(-)

diff --git a/cpu-all.h b/cpu-all.h
index e839100..9517a9b 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -920,6 +920,7 @@ extern ram_addr_t ram_size;

typedef struct RAMBlock {
uint8_t *host;
+ uint8_t *phys_dirty;
ram_addr_t offset;
ram_addr_t length;
uint32_t flags;
@@ -931,7 +932,6 @@ typedef struct RAMBlock {
} RAMBlock;

typedef struct RAMList {
- uint8_t *phys_dirty;
QLIST_HEAD(ram, RAMBlock) blocks;
} RAMList;
extern RAMList ram_list;
@@ -961,32 +961,55 @@ extern int mem_prealloc;
#define CODE_DIRTY_FLAG 0x02
#define MIGRATION_DIRTY_FLAG 0x08

+RAMBlock *qemu_addr_to_ramblock(ram_addr_t);
+
+static inline int get_page_nr(ram_addr_t addr, RAMBlock **block)
+{
+ int page_nr;
+ *block = qemu_addr_to_ramblock(addr);
+
+ page_nr = addr - (*block)->offset;
+ page_nr = page_nr >> TARGET_PAGE_BITS;
+
+ return page_nr;
+}
+
/* read dirty bit (return 0 or 1) */
static inline int cpu_physical_memory_is_dirty(ram_addr_t addr)
{
- return ram_list.phys_dirty[addr >> TARGET_PAGE_BITS] == 0xff;
+ RAMBlock *block;
+ int page_nr = get_page_nr(addr, &block);
+ return block->phys_dirty[page_nr] == 0xff;
}

static inline int cpu_physical_memory_get_dirty_flags(ram_addr_t addr)
{
- return ram_list.phys_dirty[addr >> TARGET_PAGE_BITS];
+ RAMBlock *block;
+ int page_nr = get_page_nr(addr, &block);
+ return block->phys_dirty[page_nr];
}

static inline int cpu_physical_memory_get_dirty(ram_addr_t addr,
int dirty_flags)
{
- return ram_list.phys_dirty[addr >> TARGET_PAGE_BITS] & dirty_flags;
+ RAMBlock *block;
+ int page_nr = get_page_nr(addr, &block);
+ return block->phys_dirty[page_nr] & dirty_flags;
}

static inline void cpu_physical_memory_set_dirty(ram_addr_t addr)
{
- ram_list.phys_dirty[addr >> TARGET_PAGE_BITS] = 0xff;
+ RAMBlock *block;
+ int page_nr = get_page_nr(addr, &block);
+ block->phys_dirty[page_nr] = 0xff;
}

static inline int cpu_physical_memory_set_dirty_flags(ram_addr_t addr,
int dirty_flags)
{
- return ram_list.phys_dirty[addr >> TARGET_PAGE_BITS] |= dirty_flags;
+ RAMBlock *block;
+ int page_nr = get_page_nr(addr, &block);
+ return block->phys_dirty[page_nr] |= dirty_flags;
}

static inline void cpu_physical_memory_mask_dirty_range(ram_addr_t start,
@@ -995,10 +1018,13 @@ static inline void cpu_physical_memory_mask_dirty_range(ram_addr_t start,
{
int i, mask, len;
uint8_t *p;
+ RAMBlock *block;
+ int page_nr = get_page_nr(start, &block);

len = length >> TARGET_PAGE_BITS;
mask = ~dirty_flags;
- p = ram_list.phys_dirty + (start >> TARGET_PAGE_BITS);
+
+ p = block->phys_dirty + page_nr;
for (i = 0; i < len; i++) {
p[i] &= mask;
}
diff --git a/exec.c b/exec.c
index 0e2ce57..6312550 100644
--- a/exec.c
+++ b/exec.c
@@ -2106,6 +2106,10 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
abort();
}

+ if (kvm_enabled()) {
+ return;
+ }
+
for(env = first_cpu; env != NULL; env = env->next_cpu) {
int mmu_idx;
for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
@@ -2894,17 +2898,6 @@ static ram_addr_t find_ram_offset(ram_addr_t size)
return offset;
}

-static ram_addr_t last_ram_offset(void)
-{
- RAMBlock *block;
- ram_addr_t last = 0;
-
- QLIST_FOREACH(block, &ram_list.blocks, next)
- last = MAX(last, block->offset + block->length);
-
- return last;
-}
-
ram_addr_t qemu_ram_alloc_from_ptr(DeviceState *dev, const char *name,
ram_addr_t size, void *host)
{
@@ -2974,10 +2967,8 @@ ram_addr_t qemu_ram_alloc_from_ptr(DeviceState *dev, const char *name,

QLIST_INSERT_HEAD(&ram_list.blocks, new_block, next);

- ram_list.phys_dirty = qemu_realloc(ram_list.phys_dirty,
- last_ram_offset() >> TARGET_PAGE_BITS);
- memset(ram_list.phys_dirty + (new_block->offset >> TARGET_PAGE_BITS),
- 0xff, size >> TARGET_PAGE_BITS);
+ new_block->phys_dirty = qemu_mallocz(new_block->length >> TARGET_PAGE_BITS);
+ memset(new_block->phys_dirty, 0xff, new_block->length >> TARGET_PAGE_BITS);

if (kvm_enabled())
kvm_setup_guest_memory(new_block->host, size);
@@ -3141,6 +3132,23 @@ void *qemu_get_ram_ptr(ram_addr_t addr)
return NULL;
}

+RAMBlock *qemu_addr_to_ramblock(ram_addr_t addr)
+{
+ RAMBlock *block;
+
+ QLIST_FOREACH(block, &ram_list.blocks, next) {
+ if (addr - block->offset < block->length) {
+ return block;
+ }
+ }
+
+ fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr);
+ abort();
+
+ return NULL;
+}
+
+
/* Return a host pointer to ram allocated with qemu_ram_alloc.
* Same as qemu_get_ram_ptr but avoid reordering ramblocks.
*/
diff --git a/xen-all.c b/xen-all.c
index fcb106f..6782e68 100644
--- a/xen-all.c
+++ b/xen-all.c
@@ -147,10 +147,8 @@ static void xen_ram_init(ram_addr_t ram_size)

QLIST_INSERT_HEAD(&ram_list.blocks, new_block, next);

- ram_list.phys_dirty = qemu_realloc(ram_list.phys_dirty,
- new_block->length >> TARGET_PAGE_BITS);
- memset(ram_list.phys_dirty + (new_block->offset >> TARGET_PAGE_BITS),
- 0xff, new_block->length >> TARGET_PAGE_BITS);
+ new_block->phys_dirty = qemu_mallocz(new_block->length >> TARGET_PAGE_BITS);
+ memset(new_block->phys_dirty, 0xff, new_block->length >> TARGET_PAGE_BITS);

if (ram_size >= 0xe0000000 ) {
above_4g_mem_size = ram_size - 0xe0000000;
--
1.7.4.1