* [Qemu-devel] [PATCH 4/6] memory: find dirty range
@ 2011-12-10 16:45 Blue Swirl
2011-12-11 9:30 ` Avi Kivity
0 siblings, 1 reply; 2+ messages in thread
From: Blue Swirl @ 2011-12-10 16:45 UTC (permalink / raw)
To: Avi Kivity, qemu-devel
Instead of each target knowing or guessing the guest page size,
iterate through the dirty ranges.
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
---
cpu-all.h | 30 ++++++++++++++++++++++++++++++
hw/tcx.c | 54 ++++++++++++++++++++++--------------------------------
hw/vga.c | 16 +++++++---------
memory.c | 16 ++++++++++++++++
memory.h | 24 ++++++++++++++++++++++++
5 files changed, 99 insertions(+), 41 deletions(-)
diff --git a/cpu-all.h b/cpu-all.h
index 0cb62ca..a5c6670 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -574,6 +574,36 @@ int cpu_physical_memory_set_dirty_tracking(int enable);
int cpu_physical_memory_get_dirty_tracking(void);
+static inline void cpu_physical_memory_range_find_dirty(ram_addr_t start,
+ ram_addr_t end,
+ ram_addr_t *pstart,
+ ram_addr_t *pend,
+ int flags)
+{
+ ram_addr_t idx;
+
+ start >>= TARGET_PAGE_BITS;
+ end += TARGET_PAGE_SIZE - 1;
+ end >>= TARGET_PAGE_BITS;
+
+ for (idx = start; idx < end; idx++) {
+ if (ram_list.phys_dirty[idx] & flags) {
+ *pstart = idx << TARGET_PAGE_BITS;
+ for (; idx < end; idx++) {
+ if (!(ram_list.phys_dirty[idx] & flags)) {
+ *pend = (idx << TARGET_PAGE_BITS) - 1;
+ return;
+ }
+ }
+ *pend = (end << TARGET_PAGE_BITS) - 1;
+ return;
+ }
+ }
+ /* everything pristine */
+ *pstart = (end << TARGET_PAGE_BITS) - 1;
+ *pend = (end << TARGET_PAGE_BITS) - 1;
+}
+
int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr,
target_phys_addr_t end_addr);
diff --git a/hw/tcx.c b/hw/tcx.c
index fd45ce8..d031cbd 100644
--- a/hw/tcx.c
+++ b/hw/tcx.c
@@ -212,7 +212,7 @@ static inline void reset_dirty(TCXState *ts,
ram_addr_t page_min,
static void tcx_update_display(void *opaque)
{
TCXState *ts = opaque;
- ram_addr_t page, page_min, page_max;
+ ram_addr_t page, page_min, page_max, p;
int y, y_start, dd, ds;
uint8_t *d, *s;
void (*f)(TCXState *s1, uint8_t *dst, const uint8_t *src, int width);
@@ -244,37 +244,28 @@ static void tcx_update_display(void *opaque)
return;
}
- for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) {
- if (memory_region_get_dirty(&ts->vram_mem, page, DIRTY_MEMORY_VGA)) {
- if (y_start < 0)
- y_start = y;
- if (page < page_min)
- page_min = page;
- if (page > page_max)
- page_max = page;
- f(ts, d, s, ts->width);
- d += dd;
- s += ds;
- f(ts, d, s, ts->width);
- d += dd;
- s += ds;
- f(ts, d, s, ts->width);
- d += dd;
- s += ds;
- f(ts, d, s, ts->width);
- d += dd;
- s += ds;
- } else {
- if (y_start >= 0) {
- /* flush to display */
- dpy_update(ts->ds, 0, y_start,
- ts->width, y - y_start);
- y_start = -1;
- }
- d += dd * 4;
- s += ds * 4;
+ assert(MAXX == 1024);
+ y = 0;
+ for (p = 0; p < MAXX * MAXY;) {
+ target_phys_addr_t dirty_start, dirty_end;
+
+ memory_region_find_dirty(&ts->vram_mem, p, MAXX * MAXY, &dirty_start,
+ &dirty_end, DIRTY_MEMORY_VGA);
+ if (dirty_start == MAXX * MAXY - 1) {
+ break;
+ }
+ page = dirty_start;
+ f(ts, d + (page >> 10) * dd, s + page, dirty_end - dirty_start);
+ if (y_start < 0) {
+ page_min = dirty_start;
+ /* divide by MAXX */
+ y_start = page_min >> 10;
}
+ page_max = dirty_end;
+ y = page_max >> 10;
+ p = dirty_end + 1;
}
+
if (y_start >= 0) {
/* flush to display */
dpy_update(ts->ds, 0, y_start,
@@ -282,8 +273,7 @@ static void tcx_update_display(void *opaque)
}
/* reset modified pages */
if (page_max >= page_min) {
- memory_region_reset_dirty(&ts->vram_mem,
- page_min, page_max + TARGET_PAGE_SIZE,
+ memory_region_reset_dirty(&ts->vram_mem, page_min, page_max,
DIRTY_MEMORY_VGA);
}
}
diff --git a/hw/vga.c b/hw/vga.c
index 85176a6..16c94b6 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -1731,6 +1731,8 @@ static void vga_draw_graphic(VGACommonState *s,
int full_update)
linesize = ds_get_linesize(s->ds);
y1 = 0;
for(y = 0; y < height; y++) {
+ target_phys_addr_t dirty_start, dirty_end;
+
addr = addr1;
if (!(s->cr[0x17] & 1)) {
int shift;
@@ -1741,17 +1743,13 @@ static void vga_draw_graphic(VGACommonState
*s, int full_update)
if (!(s->cr[0x17] & 2)) {
addr = (addr & ~0x8000) | ((y1 & 2) << 14);
}
+ memory_region_find_dirty(&s->vram, addr, addr + bwidth - 1,
+ &dirty_start, &dirty_end, DIRTY_MEMORY_VGA);
+ if (dirty_start < addr + bwidth - 1) {
+ update = 1;
+ }
page0 = addr & TARGET_PAGE_MASK;
page1 = (addr + bwidth - 1) & TARGET_PAGE_MASK;
- update = full_update |
- memory_region_get_dirty(&s->vram, page0, DIRTY_MEMORY_VGA) |
- memory_region_get_dirty(&s->vram, page1, DIRTY_MEMORY_VGA);
- if ((page1 - page0) > TARGET_PAGE_SIZE) {
- /* if wide line, can use another page */
- update |= memory_region_get_dirty(&s->vram,
- page0 + TARGET_PAGE_SIZE,
- DIRTY_MEMORY_VGA);
- }
/* explicit invalidation for the hardware cursor */
update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
if (update) {
diff --git a/memory.c b/memory.c
index 71600d0..af684fa 100644
--- a/memory.c
+++ b/memory.c
@@ -1068,6 +1068,22 @@ bool memory_region_get_dirty(MemoryRegion *mr,
target_phys_addr_t addr,
return cpu_physical_memory_get_dirty(mr->ram_addr + addr, 1 << client);
}
+void memory_region_find_dirty(MemoryRegion *mr, target_phys_addr_t start,
+ target_phys_addr_t end,
+ target_phys_addr_t *pstart,
+ target_phys_addr_t *pend,
+ unsigned client)
+{
+ ram_addr_t dstart, dend;
+
+ assert(mr->terminates);
+ cpu_physical_memory_range_find_dirty(mr->ram_addr + start,
+ mr->ram_addr + end, &dstart, &dend,
+ 1 << client);
+ *pstart = dstart - mr->ram_addr;
+ *pend = dend - mr->ram_addr;
+}
+
void memory_region_set_dirty(MemoryRegion *mr, target_phys_addr_t addr,
target_phys_addr_t size)
{
diff --git a/memory.h b/memory.h
index 1f8b5a5..ace2708 100644
--- a/memory.h
+++ b/memory.h
@@ -314,6 +314,30 @@ bool memory_region_get_dirty(MemoryRegion *mr,
target_phys_addr_t addr,
unsigned client);
/**
+ * memory_region_find_dirty: Find dirty ranges in a memory range for a
+ * specified client.
+ *
+ * Returns lowest contiguous dirty memory range within the specified
memory range.
+ * Dirty logging must be enabled.
+ *
+ * @mr: the memory region being queried.
+ * @start: the start address (relative to the start of the region) of the
+ * region being searched.
+ * @end: the end address (relative to the start of the region) of the
+ * region being searched.
+ * *@pstart: the returned start address (relative to the start of the region)
+ * of the lowest contiguous dirty range found, or @end if not found.
+ * *@pend: the returned end address (relative to the start of the region)
+ * of the lowest contiguous dirty range found.
+ * @client: the user of the logging information; %DIRTY_MEMORY_MIGRATION or
+ * %DIRTY_MEMORY_VGA.
+ */
+void memory_region_find_dirty(MemoryRegion *mr, target_phys_addr_t start,
+ target_phys_addr_t end,
+ target_phys_addr_t *pstart,
+ target_phys_addr_t *pend,
+ unsigned client);
+/**
* memory_region_set_dirty: Mark a page as dirty in a memory region.
*
* Marks a page as dirty, after it has been dirtied outside guest code.
--
1.7.2.5
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [Qemu-devel] [PATCH 4/6] memory: find dirty range
2011-12-10 16:45 [Qemu-devel] [PATCH 4/6] memory: find dirty range Blue Swirl
@ 2011-12-11 9:30 ` Avi Kivity
0 siblings, 0 replies; 2+ messages in thread
From: Avi Kivity @ 2011-12-11 9:30 UTC (permalink / raw)
To: Blue Swirl; +Cc: qemu-devel
On 12/10/2011 06:45 PM, Blue Swirl wrote:
> Instead of each target knowing or guessing the guest page size,
> iterate through the dirty ranges.
>
> Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
> ---
> cpu-all.h | 30 ++++++++++++++++++++++++++++++
> hw/tcx.c | 54 ++++++++++++++++++++++--------------------------------
> hw/vga.c | 16 +++++++---------
> memory.c | 16 ++++++++++++++++
> memory.h | 24 ++++++++++++++++++++++++
> 5 files changed, 99 insertions(+), 41 deletions(-)
>
> diff --git a/cpu-all.h b/cpu-all.h
> index 0cb62ca..a5c6670 100644
> --- a/cpu-all.h
> +++ b/cpu-all.h
> @@ -574,6 +574,36 @@ int cpu_physical_memory_set_dirty_tracking(int enable);
>
> int cpu_physical_memory_get_dirty_tracking(void);
>
> +static inline void cpu_physical_memory_range_find_dirty(ram_addr_t start,
> + ram_addr_t end,
> + ram_addr_t *pstart,
> + ram_addr_t *pend,
> + int flags)
> +{
> + ram_addr_t idx;
> +
> + start >>= TARGET_PAGE_BITS;
> + end += TARGET_PAGE_SIZE - 1;
> + end >>= TARGET_PAGE_BITS;
> +
> + for (idx = start; idx < end; idx++) {
> + if (ram_list.phys_dirty[idx] & flags) {
> + *pstart = idx << TARGET_PAGE_BITS;
> + for (; idx < end; idx++) {
> + if (!(ram_list.phys_dirty[idx] & flags)) {
> + *pend = (idx << TARGET_PAGE_BITS) - 1;
> + return;
> + }
> + }
> + *pend = (end << TARGET_PAGE_BITS) - 1;
This uses a convention of fully inclusive ranges, not semi inclusive
which is what we usually use.
> + return;
> + }
> + }
> + /* everything pristine */
> + *pstart = (end << TARGET_PAGE_BITS) - 1;
> + *pend = (end << TARGET_PAGE_BITS) - 1;
> +}
> +
I prefer this to be implemented using memory_region primitives, less
work for me to covert afterwards.
Also, no need to inline this.
> int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr,
> target_phys_addr_t end_addr);
>
> diff --git a/hw/tcx.c b/hw/tcx.c
> index fd45ce8..d031cbd 100644
> --- a/hw/tcx.c
> +++ b/hw/tcx.c
> @@ -212,7 +212,7 @@ static inline void reset_dirty(TCXState *ts,
> ram_addr_t page_min,
> static void tcx_update_display(void *opaque)
> {
> TCXState *ts = opaque;
> - ram_addr_t page, page_min, page_max;
> + ram_addr_t page, page_min, page_max, p;
> int y, y_start, dd, ds;
> uint8_t *d, *s;
> void (*f)(TCXState *s1, uint8_t *dst, const uint8_t *src, int width);
> @@ -244,37 +244,28 @@ static void tcx_update_display(void *opaque)
> return;
> }
>
> - for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) {
> - if (memory_region_get_dirty(&ts->vram_mem, page, DIRTY_MEMORY_VGA)) {
> - if (y_start < 0)
> - y_start = y;
> - if (page < page_min)
> - page_min = page;
> - if (page > page_max)
> - page_max = page;
> - f(ts, d, s, ts->width);
> - d += dd;
> - s += ds;
> - f(ts, d, s, ts->width);
> - d += dd;
> - s += ds;
> - f(ts, d, s, ts->width);
> - d += dd;
> - s += ds;
> - f(ts, d, s, ts->width);
> - d += dd;
> - s += ds;
> - } else {
> - if (y_start >= 0) {
> - /* flush to display */
> - dpy_update(ts->ds, 0, y_start,
> - ts->width, y - y_start);
> - y_start = -1;
> - }
> - d += dd * 4;
> - s += ds * 4;
> + assert(MAXX == 1024);
> + y = 0;
> + for (p = 0; p < MAXX * MAXY;) {
> + target_phys_addr_t dirty_start, dirty_end;
> +
> + memory_region_find_dirty(&ts->vram_mem, p, MAXX * MAXY, &dirty_start,
> + &dirty_end, DIRTY_MEMORY_VGA);
> + if (dirty_start == MAXX * MAXY - 1) {
> + break;
> + }
Gives no way to indicate that just that one byte is dirty (possible if
MAXX * MAXY == 1 (mod TARGET_PAGE_SIZE))
> + page = dirty_start;
> + f(ts, d + (page >> 10) * dd, s + page, dirty_end - dirty_start);
> + if (y_start < 0) {
> + page_min = dirty_start;
> + /* divide by MAXX */
> + y_start = page_min >> 10;
page_min / MAXX?
> }
> + page_max = dirty_end;
> + y = page_max >> 10;
> + p = dirty_end + 1;
> }
> +
> if (y_start >= 0) {
> /* flush to display */
> dpy_update(ts->ds, 0, y_start,
> @@ -282,8 +273,7 @@ static void tcx_update_display(void *opaque)
> }
> /* reset modified pages */
> if (page_max >= page_min) {
> - memory_region_reset_dirty(&ts->vram_mem,
> - page_min, page_max + TARGET_PAGE_SIZE,
> + memory_region_reset_dirty(&ts->vram_mem, page_min, page_max,
> DIRTY_MEMORY_VGA);
fully-inclusive/semi-inclusive mixup
> /**
> + * memory_region_find_dirty: Find dirty ranges in a memory range for a
> + * specified client.
> + *
> + * Returns lowest contiguous dirty memory range within the specified
> memory range.
> + * Dirty logging must be enabled.
> + *
> + * @mr: the memory region being queried.
> + * @start: the start address (relative to the start of the region) of the
> + * region being searched.
> + * @end: the end address (relative to the start of the region) of the
> + * region being searched.
> + * *@pstart: the returned start address (relative to the start of the region)
> + * of the lowest contiguous dirty range found, or @end if not found.
> + * *@pend: the returned end address (relative to the start of the region)
> + * of the lowest contiguous dirty range found.
> + * @client: the user of the logging information; %DIRTY_MEMORY_MIGRATION or
> + * %DIRTY_MEMORY_VGA.
> + */
> +void memory_region_find_dirty(MemoryRegion *mr, target_phys_addr_t start,
> + target_phys_addr_t end,
> + target_phys_addr_t *pstart,
> + target_phys_addr_t *pend,
> + unsigned client);
>
Might wrap in a MEMORY_REGION_FOR_EACH_DIRTY_RANGE() macro.
--
error compiling committee.c: too many arguments to function
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2011-12-11 9:30 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-12-10 16:45 [Qemu-devel] [PATCH 4/6] memory: find dirty range Blue Swirl
2011-12-11 9:30 ` Avi Kivity
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.