All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 00/22] Dirty bitmap atomic access and optimizations
@ 2015-03-26 17:38 Paolo Bonzini
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 01/22] memory: add memory_region_ram_resize Paolo Bonzini
                   ` (22 more replies)
  0 siblings, 23 replies; 39+ messages in thread
From: Paolo Bonzini @ 2015-03-26 17:38 UTC (permalink / raw)
  To: qemu-devel

QEMU is currently accessing the dirty bitmaps very liberally,
which is understandable since the accesses are cheap.  This is
however not good for squeezing maximum performance out of dataplane,
and is also not good if the accesses become more expensive---as is
the case when they use atomic primitives.

Patches 1-2 make acpi-build.h only use public memory APIs.

Patches 3-7 optimize access to the VGA dirty bitmap, by restricting
it to video RAM only.

Patches 8-15 optimize access to the code and migration bitmaps,
by tracking them respectively if TCG is enabled and if migration
is in progress.  Note that the first iteration of migration already
does not look at the migration bitmap (commit 70c8652, migration:
do not search dirty pages in bulk stage, 2013-03-26).

Patches 16-21 are Stefan's patches to convert bitmap access to use
atomic primitives.

While the main purpose of these patches is a working dirty bitmap
for dataplane (and possibly multithreaded TCG), there's something
that they are immediately useful for: patch 22 makes the migration
thread synchronize the bitmap outside the big QEMU lock, thus
removing the last source of jitter during the RAM copy phase of
migration.

Please review and test! (it's available as branch "atomic-dirty"
on my github repository)  In particular, I suspect that the
postcopy patches might be good at finding bugs.

Paolo

Paolo Bonzini (16):
  memory: add memory_region_ram_resize
  acpi-build: remove dependency from ram_addr.h
  memory: the only dirty memory flag for users is DIRTY_MEMORY_VGA
  display: enable DIRTY_MEMORY_VGA tracking explicitly
  memory: return bitmap from memory_region_is_logging
  framebuffer: check memory_region_is_logging
  ui/console: check memory_region_is_logging
  memory: track DIRTY_MEMORY_CODE in mr->dirty_log_mask
  memory: return DIRTY_MEMORY_MIGRATION from memory_region_is_logging
  ram_addr: tweaks to xen_modified_memory
  exec: simplify notdirty_mem_write
  exec: use memory_region_is_logging to optimize dirty tracking
  exec: pass client mask to cpu_physical_memory_set_dirty_range
  exec: only check relevant bitmaps for cleanliness
  memory: do not touch code dirty bitmap unless TCG is enabled
  migration: run bitmap sync outside iothread lock

Stefan Hajnoczi (6):
  bitmap: add atomic set functions
  bitmap: add atomic test and clear
  memory: use atomic ops for setting dirty memory bits
  migration: move dirty bitmap sync to ram_addr.h
  memory: replace cpu_physical_memory_reset_dirty() with test-and-clear
  memory: make cpu_physical_memory_sync_dirty_bitmap() fully atomic

 arch_init.c                  |  56 +++----------------
 cputlb.c                     |   4 +-
 exec.c                       | 103 ++++++++++++++++------------------
 hw/core/loader.c             |   8 +--
 hw/display/cg3.c             |   1 +
 hw/display/exynos4210_fimd.c |   7 ++-
 hw/display/framebuffer.c     |  23 ++++++--
 hw/display/g364fb.c          |   2 +-
 hw/display/sm501.c           |   1 +
 hw/display/tcx.c             |   1 +
 hw/display/vmware_vga.c      |   2 +-
 hw/i386/acpi-build.c         |  36 ++++++------
 hw/virtio/vhost.c            |   3 +-
 include/exec/memory.h        |  27 +++++++--
 include/exec/ram_addr.h      | 128 ++++++++++++++++++++++++++++---------------
 include/hw/loader.h          |   8 ++-
 include/qemu/bitmap.h        |   4 ++
 include/qemu/bitops.h        |  14 +++++
 kvm-all.c                    |   3 +-
 memory.c                     |  34 ++++++++----
 ui/console.c                 |  14 +++--
 util/bitmap.c                |  78 ++++++++++++++++++++++++++
 xen-hvm.c                    |   3 +-
 23 files changed, 356 insertions(+), 204 deletions(-)

-- 
2.3.3

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [Qemu-devel] [PATCH 01/22] memory: add memory_region_ram_resize
  2015-03-26 17:38 [Qemu-devel] [PATCH 00/22] Dirty bitmap atomic access and optimizations Paolo Bonzini
@ 2015-03-26 17:38 ` Paolo Bonzini
  2015-03-28 18:58   ` Michael S. Tsirkin
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 02/22] acpi-build: remove dependency from ram_addr.h Paolo Bonzini
                   ` (21 subsequent siblings)
  22 siblings, 1 reply; 39+ messages in thread
From: Paolo Bonzini @ 2015-03-26 17:38 UTC (permalink / raw)
  To: qemu-devel; +Cc: Michael S. Tsirkin

This is a simple MemoryRegion wrapper for qemu_ram_resize.

Cc: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 include/exec/memory.h | 12 ++++++++++++
 memory.c              |  7 +++++++
 2 files changed, 19 insertions(+)

diff --git a/include/exec/memory.h b/include/exec/memory.h
index 06ffa1d..a2ea587 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -605,6 +605,18 @@ int memory_region_get_fd(MemoryRegion *mr);
  */
 void *memory_region_get_ram_ptr(MemoryRegion *mr);
 
+/* memory_region_ram_resize: Resize a RAM region.
+ *
+ * Only legal before guest might have detected the memory size: e.g. on
+ * incoming migration, or right after reset.
+ *
+ * @mr: a memory region created with @memory_region_init_resizeable_ram.
+ * @newsize: the new size the region
+ * @errp: pointer to Error*, to store an error if it happens.
+ */
+void memory_region_ram_resize(MemoryRegion *mr, ram_addr_t newsize,
+                              Error **errp);
+
 /**
  * memory_region_set_log: Turn dirty logging on or off for a region.
  *
diff --git a/memory.c b/memory.c
index ee3f2a8..a11e9bf 100644
--- a/memory.c
+++ b/memory.c
@@ -1452,6 +1452,13 @@ void *memory_region_get_ram_ptr(MemoryRegion *mr)
     return qemu_get_ram_ptr(mr->ram_addr & TARGET_PAGE_MASK);
 }
 
+void memory_region_ram_resize(MemoryRegion *mr, ram_addr_t newsize, Error **errp)
+{
+    assert(mr->terminates);
+
+    qemu_ram_resize(mr->ram_addr, newsize, errp);
+}
+
 static void memory_region_update_coalesced_range_as(MemoryRegion *mr, AddressSpace *as)
 {
     FlatView *view;
-- 
2.3.3

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [Qemu-devel] [PATCH 02/22] acpi-build: remove dependency from ram_addr.h
  2015-03-26 17:38 [Qemu-devel] [PATCH 00/22] Dirty bitmap atomic access and optimizations Paolo Bonzini
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 01/22] memory: add memory_region_ram_resize Paolo Bonzini
@ 2015-03-26 17:38 ` Paolo Bonzini
  2015-03-28 18:58   ` Michael S. Tsirkin
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 03/22] memory: the only dirty memory flag for users is DIRTY_MEMORY_VGA Paolo Bonzini
                   ` (20 subsequent siblings)
  22 siblings, 1 reply; 39+ messages in thread
From: Paolo Bonzini @ 2015-03-26 17:38 UTC (permalink / raw)
  To: qemu-devel; +Cc: Michael S. Tsirkin

ram_addr_t is an internal interface, everyone should go through
MemoryRegion.  Clean it up by making rom_add_blob return a
MemoryRegion* and using the new qemu_ram_resize infrastructure.

Cc: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/core/loader.c     |  8 ++++----
 hw/i386/acpi-build.c | 36 ++++++++++++++++++------------------
 include/hw/loader.h  |  8 +++++---
 3 files changed, 27 insertions(+), 25 deletions(-)

diff --git a/hw/core/loader.c b/hw/core/loader.c
index d4c441f..7ee675c 100644
--- a/hw/core/loader.c
+++ b/hw/core/loader.c
@@ -835,12 +835,12 @@ err:
     return -1;
 }
 
-ram_addr_t rom_add_blob(const char *name, const void *blob, size_t len,
+MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len,
                    size_t max_len, hwaddr addr, const char *fw_file_name,
                    FWCfgReadCallback fw_callback, void *callback_opaque)
 {
     Rom *rom;
-    ram_addr_t ret = RAM_ADDR_MAX;
+    MemoryRegion *mr = NULL;
 
     rom           = g_malloc0(sizeof(*rom));
     rom->name     = g_strdup(name);
@@ -858,7 +858,7 @@ ram_addr_t rom_add_blob(const char *name, const void *blob, size_t len,
 
         if (rom_file_has_mr) {
             data = rom_set_mr(rom, OBJECT(fw_cfg), devpath);
-            ret = memory_region_get_ram_addr(rom->mr);
+            mr = rom->mr;
         } else {
             data = rom->data;
         }
@@ -867,7 +867,7 @@ ram_addr_t rom_add_blob(const char *name, const void *blob, size_t len,
                                  fw_callback, callback_opaque,
                                  data, rom->datasize);
     }
-    return ret;
+    return mr;
 }
 
 /* This function is specific for elf program because we don't need to allocate
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index d0a5c85..ec4d1e8 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -58,7 +58,6 @@
 
 #include "qapi/qmp/qint.h"
 #include "qom/qom-qobject.h"
-#include "exec/ram_addr.h"
 
 /* These are used to size the ACPI tables for -M pc-i440fx-1.7 and
  * -M pc-i440fx-2.0.  Even if the actual amount of AML generated grows
@@ -1323,13 +1322,13 @@ static inline void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool mfre)
 typedef
 struct AcpiBuildState {
     /* Copy of table in RAM (for patching). */
-    ram_addr_t table_ram;
+    MemoryRegion *table_mr;
     /* Is table patched? */
     uint8_t patched;
     PcGuestInfo *guest_info;
     void *rsdp;
-    ram_addr_t rsdp_ram;
-    ram_addr_t linker_ram;
+    MemoryRegion *rsdp_mr;
+    MemoryRegion *linker_mr;
 } AcpiBuildState;
 
 static bool acpi_get_mcfg(AcpiMcfgInfo *mcfg)
@@ -1513,15 +1512,15 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables)
     g_array_free(table_offsets, true);
 }
 
-static void acpi_ram_update(ram_addr_t ram, GArray *data)
+static void acpi_ram_update(MemoryRegion *mr, GArray *data)
 {
     uint32_t size = acpi_data_len(data);
 
     /* Make sure RAM size is correct - in case it got changed e.g. by migration */
-    qemu_ram_resize(ram, size, &error_abort);
+    memory_region_ram_resize(mr, size, &error_abort);
 
-    memcpy(qemu_get_ram_ptr(ram), data->data, size);
-    cpu_physical_memory_set_dirty_range_nocode(ram, size);
+    memcpy(memory_region_get_ram_ptr(mr), data->data, size);
+    memory_region_set_dirty(mr, 0, size);
 }
 
 static void acpi_build_update(void *build_opaque, uint32_t offset)
@@ -1539,15 +1538,15 @@ static void acpi_build_update(void *build_opaque, uint32_t offset)
 
     acpi_build(build_state->guest_info, &tables);
 
-    acpi_ram_update(build_state->table_ram, tables.table_data);
+    acpi_ram_update(build_state->table_mr, tables.table_data);
 
     if (build_state->rsdp) {
         memcpy(build_state->rsdp, tables.rsdp->data, acpi_data_len(tables.rsdp));
     } else {
-        acpi_ram_update(build_state->rsdp_ram, tables.rsdp);
+        acpi_ram_update(build_state->rsdp_mr, tables.rsdp);
     }
 
-    acpi_ram_update(build_state->linker_ram, tables.linker);
+    acpi_ram_update(build_state->linker_mr, tables.linker);
     acpi_build_tables_cleanup(&tables, true);
 }
 
@@ -1557,8 +1556,9 @@ static void acpi_build_reset(void *build_opaque)
     build_state->patched = 0;
 }
 
-static ram_addr_t acpi_add_rom_blob(AcpiBuildState *build_state, GArray *blob,
-                               const char *name, uint64_t max_size)
+static MemoryRegion *acpi_add_rom_blob(AcpiBuildState *build_state,
+                                       GArray *blob, const char *name,
+                                       uint64_t max_size)
 {
     return rom_add_blob(name, blob->data, acpi_data_len(blob), max_size, -1,
                         name, acpi_build_update, build_state);
@@ -1604,12 +1604,12 @@ void acpi_setup(PcGuestInfo *guest_info)
     acpi_build(build_state->guest_info, &tables);
 
     /* Now expose it all to Guest */
-    build_state->table_ram = acpi_add_rom_blob(build_state, tables.table_data,
+    build_state->table_mr = acpi_add_rom_blob(build_state, tables.table_data,
                                                ACPI_BUILD_TABLE_FILE,
                                                ACPI_BUILD_TABLE_MAX_SIZE);
-    assert(build_state->table_ram != RAM_ADDR_MAX);
+    assert(build_state->table_mr != NULL);
 
-    build_state->linker_ram =
+    build_state->linker_mr =
         acpi_add_rom_blob(build_state, tables.linker, "etc/table-loader", 0);
 
     fw_cfg_add_file(guest_info->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
@@ -1627,10 +1627,10 @@ void acpi_setup(PcGuestInfo *guest_info)
         fw_cfg_add_file_callback(guest_info->fw_cfg, ACPI_BUILD_RSDP_FILE,
                                  acpi_build_update, build_state,
                                  build_state->rsdp, rsdp_size);
-        build_state->rsdp_ram = (ram_addr_t)-1;
+        build_state->rsdp_mr = NULL;
     } else {
         build_state->rsdp = NULL;
-        build_state->rsdp_ram = acpi_add_rom_blob(build_state, tables.rsdp,
+        build_state->rsdp_mr = acpi_add_rom_blob(build_state, tables.rsdp,
                                                   ACPI_BUILD_RSDP_FILE, 0);
     }
 
diff --git a/include/hw/loader.h b/include/hw/loader.h
index 4f0681b..485ff8f 100644
--- a/include/hw/loader.h
+++ b/include/hw/loader.h
@@ -68,9 +68,11 @@ extern bool rom_file_has_mr;
 int rom_add_file(const char *file, const char *fw_dir,
                  hwaddr addr, int32_t bootindex,
                  bool option_rom);
-ram_addr_t rom_add_blob(const char *name, const void *blob, size_t len,
-                   size_t max_len, hwaddr addr, const char *fw_file_name,
-                   FWCfgReadCallback fw_callback, void *callback_opaque);
+MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len,
+                           size_t max_len, hwaddr addr,
+                           const char *fw_file_name,
+                           FWCfgReadCallback fw_callback,
+                           void *callback_opaque);
 int rom_add_elf_program(const char *name, void *data, size_t datasize,
                         size_t romsize, hwaddr addr);
 int rom_load_all(void);
-- 
2.3.3

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [Qemu-devel] [PATCH 03/22] memory: the only dirty memory flag for users is DIRTY_MEMORY_VGA
  2015-03-26 17:38 [Qemu-devel] [PATCH 00/22] Dirty bitmap atomic access and optimizations Paolo Bonzini
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 01/22] memory: add memory_region_ram_resize Paolo Bonzini
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 02/22] acpi-build: remove dependency from ram_addr.h Paolo Bonzini
@ 2015-03-26 17:38 ` Paolo Bonzini
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 04/22] display: enable DIRTY_MEMORY_VGA tracking explicitly Paolo Bonzini
                   ` (19 subsequent siblings)
  22 siblings, 0 replies; 39+ messages in thread
From: Paolo Bonzini @ 2015-03-26 17:38 UTC (permalink / raw)
  To: qemu-devel

DIRTY_MEMORY_MIGRATION is triggered by memory_global_dirty_log_start
and memory_global_dirty_log_stop, so it cannot be used with
memory_region_set_log.

Specify this in the documentation and assert it.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 include/exec/memory.h | 3 +--
 memory.c              | 1 +
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/include/exec/memory.h b/include/exec/memory.h
index a2ea587..081f7d6 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -625,8 +625,7 @@ void memory_region_ram_resize(MemoryRegion *mr, ram_addr_t newsize,
  *
  * @mr: the memory region being updated.
  * @log: whether dirty logging is to be enabled or disabled.
- * @client: the user of the logging information; %DIRTY_MEMORY_MIGRATION or
- *          %DIRTY_MEMORY_VGA.
+ * @client: the user of the logging information; %DIRTY_MEMORY_VGA only.
  */
 void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client);
 
diff --git a/memory.c b/memory.c
index a11e9bf..e688f5e 100644
--- a/memory.c
+++ b/memory.c
@@ -1354,6 +1354,7 @@ void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client)
 {
     uint8_t mask = 1 << client;
 
+    assert(client == DIRTY_MEMORY_VGA);
     memory_region_transaction_begin();
     mr->dirty_log_mask = (mr->dirty_log_mask & ~mask) | (log * mask);
     memory_region_update_pending |= mr->enabled;
-- 
2.3.3

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [Qemu-devel] [PATCH 04/22] display: enable DIRTY_MEMORY_VGA tracking explicitly
  2015-03-26 17:38 [Qemu-devel] [PATCH 00/22] Dirty bitmap atomic access and optimizations Paolo Bonzini
                   ` (2 preceding siblings ...)
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 03/22] memory: the only dirty memory flag for users is DIRTY_MEMORY_VGA Paolo Bonzini
@ 2015-03-26 17:38 ` Paolo Bonzini
  2015-04-20 13:11   ` Stefan Hajnoczi
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 05/22] memory: return bitmap from memory_region_is_logging Paolo Bonzini
                   ` (18 subsequent siblings)
  22 siblings, 1 reply; 39+ messages in thread
From: Paolo Bonzini @ 2015-03-26 17:38 UTC (permalink / raw)
  To: qemu-devel

This will be required soon by the memory core.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/display/cg3.c             | 1 +
 hw/display/exynos4210_fimd.c | 7 ++++++-
 hw/display/g364fb.c          | 2 +-
 hw/display/sm501.c           | 1 +
 hw/display/tcx.c             | 1 +
 5 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/hw/display/cg3.c b/hw/display/cg3.c
index 1e6ff2b..cbcf518 100644
--- a/hw/display/cg3.c
+++ b/hw/display/cg3.c
@@ -309,6 +309,7 @@ static void cg3_realizefn(DeviceState *dev, Error **errp)
 
     memory_region_init_ram(&s->vram_mem, NULL, "cg3.vram", s->vram_size,
                            &error_abort);
+    memory_region_set_log(&s->vram_mem, true, DIRTY_MEMORY_VGA);
     vmstate_register_ram_global(&s->vram_mem);
     sysbus_init_mmio(sbd, &s->vram_mem);
 
diff --git a/hw/display/exynos4210_fimd.c b/hw/display/exynos4210_fimd.c
index 45c62af..f01d084 100644
--- a/hw/display/exynos4210_fimd.c
+++ b/hw/display/exynos4210_fimd.c
@@ -1136,7 +1136,11 @@ static void fimd_update_memory_section(Exynos4210fimdState *s, unsigned win)
     /* TODO: add .exit and unref the region there.  Not needed yet since sysbus
      * does not support hot-unplug.
      */
-    memory_region_unref(w->mem_section.mr);
+    if (w->mem_section.mr) {
+        memory_region_set_log(w->mem_section.mr, false, DIRTY_MEMORY_VGA);
+        memory_region_unref(w->mem_section.mr);
+    }
+
     w->mem_section = memory_region_find(sysbus_address_space(sbd),
                                         fb_start_addr, w->fb_len);
     assert(w->mem_section.mr);
@@ -1162,6 +1166,7 @@ static void fimd_update_memory_section(Exynos4210fimdState *s, unsigned win)
         cpu_physical_memory_unmap(w->host_fb_addr, fb_mapped_len, 0, 0);
         goto error_return;
     }
+    memory_region_set_log(w->mem_section.mr, true, DIRTY_MEMORY_VGA);
     return;
 
 error_return:
diff --git a/hw/display/g364fb.c b/hw/display/g364fb.c
index 46f7b41..be62dd6 100644
--- a/hw/display/g364fb.c
+++ b/hw/display/g364fb.c
@@ -489,7 +489,7 @@ static void g364fb_init(DeviceState *dev, G364State *s)
     memory_region_init_ram_ptr(&s->mem_vram, NULL, "vram",
                                s->vram_size, s->vram);
     vmstate_register_ram(&s->mem_vram, dev);
-    memory_region_set_coalescing(&s->mem_vram);
+    memory_region_set_log(&s->mem_vram, true, DIRTY_MEMORY_VGA);
 }
 
 #define TYPE_G364 "sysbus-g364"
diff --git a/hw/display/sm501.c b/hw/display/sm501.c
index c72154b..43f8538 100644
--- a/hw/display/sm501.c
+++ b/hw/display/sm501.c
@@ -1412,6 +1412,7 @@ void sm501_init(MemoryRegion *address_space_mem, uint32_t base,
     memory_region_init_ram(&s->local_mem_region, NULL, "sm501.local",
                            local_mem_bytes, &error_abort);
     vmstate_register_ram_global(&s->local_mem_region);
+    memory_region_set_log(&s->local_mem_region, true, DIRTY_MEMORY_VGA);
     s->local_mem = memory_region_get_ram_ptr(&s->local_mem_region);
     memory_region_add_subregion(address_space_mem, base, &s->local_mem_region);
 
diff --git a/hw/display/tcx.c b/hw/display/tcx.c
index a9f9f66..58faa96 100644
--- a/hw/display/tcx.c
+++ b/hw/display/tcx.c
@@ -1006,6 +1006,7 @@ static void tcx_realizefn(DeviceState *dev, Error **errp)
     memory_region_init_ram(&s->vram_mem, OBJECT(s), "tcx.vram",
                            s->vram_size * (1 + 4 + 4), &error_abort);
     vmstate_register_ram_global(&s->vram_mem);
+    memory_region_set_log(&s->vram_mem, true, DIRTY_MEMORY_VGA);
     vram_base = memory_region_get_ram_ptr(&s->vram_mem);
 
     /* 10/ROM : FCode ROM */
-- 
2.3.3

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [Qemu-devel] [PATCH 05/22] memory: return bitmap from memory_region_is_logging
  2015-03-26 17:38 [Qemu-devel] [PATCH 00/22] Dirty bitmap atomic access and optimizations Paolo Bonzini
                   ` (3 preceding siblings ...)
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 04/22] display: enable DIRTY_MEMORY_VGA tracking explicitly Paolo Bonzini
@ 2015-03-26 17:38 ` Paolo Bonzini
  2015-03-27  5:44   ` Fam Zheng
  2015-03-28 18:54   ` Michael S. Tsirkin
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 06/22] framebuffer: check memory_region_is_logging Paolo Bonzini
                   ` (17 subsequent siblings)
  22 siblings, 2 replies; 39+ messages in thread
From: Paolo Bonzini @ 2015-03-26 17:38 UTC (permalink / raw)
  To: qemu-devel; +Cc: Michael S. Tsirkin

For now it only returns (1 << DIRTY_MEMORY_VGA) or 0, but this
will change soon so adjust the callers.

Listeners check for "any bit except migration", which is handled
via the global start/stop listener callbacks.  This in practice
means VGA because the code bitmap is TCG-specific; however, be
explicit, as for example things would be different if vhost ever
ran with TCG.

Instead, the VMware VGA is looking explicitly for DIRTY_MEMORY_VGA.

Cc: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
        This is the ugliest patch in the series.  My long-term plan
        is to get rid of the global start/stop hooks in the
        MemoryListeners.

 hw/display/vmware_vga.c | 2 +-
 hw/virtio/vhost.c       | 3 ++-
 include/exec/memory.h   | 5 +++--
 kvm-all.c               | 3 ++-
 memory.c                | 2 +-
 xen-hvm.c               | 3 ++-
 6 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c
index c17ddd1..93d7426 100644
--- a/hw/display/vmware_vga.c
+++ b/hw/display/vmware_vga.c
@@ -1124,7 +1124,7 @@ static void vmsvga_update_display(void *opaque)
      * Is it more efficient to look at vram VGA-dirty bits or wait
      * for the driver to issue SVGA_CMD_UPDATE?
      */
-    if (memory_region_is_logging(&s->vga.vram)) {
+    if (memory_region_is_logging(&s->vga.vram) & (1 << DIRTY_MEMORY_VGA)) {
         vga_sync_dirty_bitmap(&s->vga);
         dirty = memory_region_get_dirty(&s->vga.vram, 0,
             surface_stride(surface) * surface_height(surface),
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index 5a12861..59321ee 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -377,7 +377,8 @@ static void vhost_set_memory(MemoryListener *listener,
                                          memory_listener);
     hwaddr start_addr = section->offset_within_address_space;
     ram_addr_t size = int128_get64(section->size);
-    bool log_dirty = memory_region_is_logging(section->mr);
+    bool log_dirty =
+        memory_region_is_logging(section->mr) & ~(1 << DIRTY_MEMORY_MIGRATION);
     int s = offsetof(struct vhost_memory, regions) +
         (dev->mem->nregions + 1) * sizeof dev->mem->regions[0];
     void *ram;
diff --git a/include/exec/memory.h b/include/exec/memory.h
index 081f7d6..8d5feb2 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -569,11 +569,12 @@ const char *memory_region_name(const MemoryRegion *mr);
 /**
  * memory_region_is_logging: return whether a memory region is logging writes
  *
- * Returns %true if the memory region is logging writes
+ * Returns a bitmap of clients for which the memory region is logging writes.
+ * Right now this will be either 0 or (1 << DIRTY_MEMORY_VGA).
  *
  * @mr: the memory region being queried
  */
-bool memory_region_is_logging(MemoryRegion *mr);
+uint8_t memory_region_is_logging(MemoryRegion *mr);
 
 /**
  * memory_region_is_rom: check whether a memory region is ROM
diff --git a/kvm-all.c b/kvm-all.c
index 335438a..6962653 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -663,7 +663,8 @@ static void kvm_set_phys_mem(MemoryRegionSection *section, bool add)
     KVMSlot *mem, old;
     int err;
     MemoryRegion *mr = section->mr;
-    bool log_dirty = memory_region_is_logging(mr);
+    bool log_dirty =
+        memory_region_is_logging(mr) & ~(1 << DIRTY_MEMORY_MIGRATION);
     bool writeable = !mr->readonly && !mr->rom_device;
     bool readonly_flag = mr->readonly || memory_region_is_romd(mr);
     hwaddr start_addr = section->offset_within_address_space;
diff --git a/memory.c b/memory.c
index e688f5e..45606bc 100644
--- a/memory.c
+++ b/memory.c
@@ -1318,7 +1318,7 @@ bool memory_region_is_skip_dump(MemoryRegion *mr)
     return mr->skip_dump;
 }
 
-bool memory_region_is_logging(MemoryRegion *mr)
+uint8_t memory_region_is_logging(MemoryRegion *mr)
 {
     return mr->dirty_log_mask;
 }
diff --git a/xen-hvm.c b/xen-hvm.c
index 315864c..acd89c8 100644
--- a/xen-hvm.c
+++ b/xen-hvm.c
@@ -488,7 +488,8 @@ static void xen_set_memory(struct MemoryListener *listener,
     XenIOState *state = container_of(listener, XenIOState, memory_listener);
     hwaddr start_addr = section->offset_within_address_space;
     ram_addr_t size = int128_get64(section->size);
-    bool log_dirty = memory_region_is_logging(section->mr);
+    bool log_dirty =
+        memory_region_is_logging(section->mr) & ~(1 << DIRTY_MEMORY_MIGRATION);
     hvmmem_type_t mem_type;
 
     if (section->mr == &ram_memory) {
-- 
2.3.3

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [Qemu-devel] [PATCH 06/22] framebuffer: check memory_region_is_logging
  2015-03-26 17:38 [Qemu-devel] [PATCH 00/22] Dirty bitmap atomic access and optimizations Paolo Bonzini
                   ` (4 preceding siblings ...)
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 05/22] memory: return bitmap from memory_region_is_logging Paolo Bonzini
@ 2015-03-26 17:38 ` Paolo Bonzini
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 07/22] ui/console: " Paolo Bonzini
                   ` (16 subsequent siblings)
  22 siblings, 0 replies; 39+ messages in thread
From: Paolo Bonzini @ 2015-03-26 17:38 UTC (permalink / raw)
  To: qemu-devel

framebuffer.c expects DIRTY_MEMORY_VGA logging to be always on, but that
will not be the case soon.  Because framebuffer.c computes the memory
region on the fly for every update (with memory_region_find), it cannot
enable/disable logging by itself.

Instead, always treat updates as invalidations if dirty logging is
not enabled, assuming that the board will enable logging on the
RAM region that includes the framebuffer.

To simplify the code, replace memory_region_get_dirty with
memory_region_test_and_clear_dirty.  Then memory_region_reset_dirty
is only needed in the invalidate case.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/display/framebuffer.c | 23 +++++++++++++++++------
 1 file changed, 17 insertions(+), 6 deletions(-)

diff --git a/hw/display/framebuffer.c b/hw/display/framebuffer.c
index 4546e42..49fe204 100644
--- a/hw/display/framebuffer.c
+++ b/hw/display/framebuffer.c
@@ -62,7 +62,16 @@ void framebuffer_update_display(
     assert(mem);
     assert(mem_section.offset_within_address_space == base);
 
-    memory_region_sync_dirty_bitmap(mem);
+    if (memory_region_is_logging(mem) & (1 << DIRTY_MEMORY_VGA)) {
+         memory_region_sync_dirty_bitmap(mem);
+         if (invalidate) {
+             memory_region_reset_dirty(mem, mem_section.offset_within_region,
+                                       src_len, DIRTY_MEMORY_VGA);
+         }
+    } else {
+        invalidate = true;
+    }
+
     src_base = cpu_physical_memory_map(base, &src_len, 0);
     /* If we can't map the framebuffer then bail.  We could try harder,
        but it's not really worth it as dirty flag tracking will probably
@@ -88,9 +97,13 @@ void framebuffer_update_display(
     dest += i * dest_row_pitch;
 
     for (; i < rows; i++) {
-        dirty = memory_region_get_dirty(mem, addr, src_width,
-                                             DIRTY_MEMORY_VGA);
-        if (dirty || invalidate) {
+        if (invalidate) {
+            dirty = true;
+        } else {
+            dirty = memory_region_test_and_clear_dirty(mem, addr, src_width,
+                                                       DIRTY_MEMORY_VGA);
+        }
+        if (dirty) {
             fn(opaque, dest, src, cols, dest_col_pitch);
             if (first == -1)
                 first = i;
@@ -104,8 +117,6 @@ void framebuffer_update_display(
     if (first < 0) {
         goto out;
     }
-    memory_region_reset_dirty(mem, mem_section.offset_within_region, src_len,
-                              DIRTY_MEMORY_VGA);
     *first_row = first;
     *last_row = last;
 out:
-- 
2.3.3

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [Qemu-devel] [PATCH 07/22] ui/console: check memory_region_is_logging
  2015-03-26 17:38 [Qemu-devel] [PATCH 00/22] Dirty bitmap atomic access and optimizations Paolo Bonzini
                   ` (5 preceding siblings ...)
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 06/22] framebuffer: check memory_region_is_logging Paolo Bonzini
@ 2015-03-26 17:38 ` Paolo Bonzini
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 08/22] memory: track DIRTY_MEMORY_CODE in mr->dirty_log_mask Paolo Bonzini
                   ` (15 subsequent siblings)
  22 siblings, 0 replies; 39+ messages in thread
From: Paolo Bonzini @ 2015-03-26 17:38 UTC (permalink / raw)
  To: qemu-devel

dpy_gfx_update_dirty expects DIRTY_MEMORY_VGA logging to be always on,
but that will not be the case soon.  Because it computes the memory
region on the fly for every update (with memory_region_find), it cannot
enable/disable logging by itself.

Instead, always treat updates as invalidations if dirty logging is
not enabled, assuming that the board will enable logging on the
RAM region that includes the framebuffer.

To simplify the code, replace memory_region_get_dirty with
memory_region_test_and_clear_dirty.  Then memory_region_reset_dirty
is only needed in the invalidate case.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 ui/console.c | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/ui/console.c b/ui/console.c
index b15ca87..2241b32 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -1627,14 +1627,22 @@ void dpy_gfx_update_dirty(QemuConsole *con,
     }
     assert(mem);
 
-    memory_region_sync_dirty_bitmap(mem);
+    if (memory_region_is_logging(mem)) {
+        memory_region_sync_dirty_bitmap(mem);
+        if (invalidate) {
+            memory_region_reset_dirty(mem, mem_section.offset_within_region, size,
+                                      DIRTY_MEMORY_VGA);
+        }
+    } else {
+        invalidate = true;
+    }
     addr = mem_section.offset_within_region;
 
     first = -1;
     last = -1;
     for (i = 0; i < height; i++, addr += width) {
         dirty = invalidate ||
-            memory_region_get_dirty(mem, addr, width, DIRTY_MEMORY_VGA);
+            memory_region_test_and_clear_dirty(mem, addr, width, DIRTY_MEMORY_VGA);
         if (dirty) {
             if (first == -1) {
                 first = i;
@@ -1654,8 +1662,6 @@ void dpy_gfx_update_dirty(QemuConsole *con,
                        last - first + 1);
     }
 
-    memory_region_reset_dirty(mem, mem_section.offset_within_region, size,
-                              DIRTY_MEMORY_VGA);
 out:
     memory_region_unref(mem);
 }
-- 
2.3.3

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [Qemu-devel] [PATCH 08/22] memory: track DIRTY_MEMORY_CODE in mr->dirty_log_mask
  2015-03-26 17:38 [Qemu-devel] [PATCH 00/22] Dirty bitmap atomic access and optimizations Paolo Bonzini
                   ` (6 preceding siblings ...)
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 07/22] ui/console: " Paolo Bonzini
@ 2015-03-26 17:38 ` Paolo Bonzini
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 09/22] memory: return DIRTY_MEMORY_MIGRATION from memory_region_is_logging Paolo Bonzini
                   ` (14 subsequent siblings)
  22 siblings, 0 replies; 39+ messages in thread
From: Paolo Bonzini @ 2015-03-26 17:38 UTC (permalink / raw)
  To: qemu-devel

DIRTY_MEMORY_CODE is only needed for TCG.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 include/exec/memory.h | 1 -
 memory.c              | 4 ++++
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/include/exec/memory.h b/include/exec/memory.h
index 8d5feb2..aa46a52 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -570,7 +570,6 @@ const char *memory_region_name(const MemoryRegion *mr);
  * memory_region_is_logging: return whether a memory region is logging writes
  *
  * Returns a bitmap of clients for which the memory region is logging writes.
- * Right now this will be either 0 or (1 << DIRTY_MEMORY_VGA).
  *
  * @mr: the memory region being queried
  */
diff --git a/memory.c b/memory.c
index 45606bc..3864667 100644
--- a/memory.c
+++ b/memory.c
@@ -1136,6 +1136,7 @@ void memory_region_init_ram(MemoryRegion *mr,
     mr->terminates = true;
     mr->destructor = memory_region_destructor_ram;
     mr->ram_addr = qemu_ram_alloc(size, mr, errp);
+    mr->dirty_log_mask = tcg_enabled() ? (1 << DIRTY_MEMORY_CODE) : 0;
 }
 
 void memory_region_init_resizeable_ram(MemoryRegion *mr,
@@ -1153,6 +1154,7 @@ void memory_region_init_resizeable_ram(MemoryRegion *mr,
     mr->terminates = true;
     mr->destructor = memory_region_destructor_ram;
     mr->ram_addr = qemu_ram_alloc_resizeable(size, max_size, resized, mr, errp);
+    mr->dirty_log_mask = tcg_enabled() ? (1 << DIRTY_MEMORY_CODE) : 0;
 }
 
 #ifdef __linux__
@@ -1169,6 +1171,7 @@ void memory_region_init_ram_from_file(MemoryRegion *mr,
     mr->terminates = true;
     mr->destructor = memory_region_destructor_ram;
     mr->ram_addr = qemu_ram_alloc_from_file(size, mr, share, path, errp);
+    mr->dirty_log_mask = tcg_enabled() ? (1 << DIRTY_MEMORY_CODE) : 0;
 }
 #endif
 
@@ -1182,6 +1185,7 @@ void memory_region_init_ram_ptr(MemoryRegion *mr,
     mr->ram = true;
     mr->terminates = true;
     mr->destructor = memory_region_destructor_ram_from_ptr;
+    mr->dirty_log_mask = tcg_enabled() ? (1 << DIRTY_MEMORY_CODE) : 0;
 
     /* qemu_ram_alloc_from_ptr cannot fail with ptr != NULL.  */
     assert(ptr != NULL);
-- 
2.3.3

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [Qemu-devel] [PATCH 09/22] memory: return DIRTY_MEMORY_MIGRATION from memory_region_is_logging
  2015-03-26 17:38 [Qemu-devel] [PATCH 00/22] Dirty bitmap atomic access and optimizations Paolo Bonzini
                   ` (7 preceding siblings ...)
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 08/22] memory: track DIRTY_MEMORY_CODE in mr->dirty_log_mask Paolo Bonzini
@ 2015-03-26 17:38 ` Paolo Bonzini
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 10/22] ram_addr: tweaks to xen_modified_memory Paolo Bonzini
                   ` (13 subsequent siblings)
  22 siblings, 0 replies; 39+ messages in thread
From: Paolo Bonzini @ 2015-03-26 17:38 UTC (permalink / raw)
  To: qemu-devel

This will be used to make the setting of bitmaps conditional.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 memory.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/memory.c b/memory.c
index 3864667..76da05b 100644
--- a/memory.c
+++ b/memory.c
@@ -1324,7 +1324,11 @@ bool memory_region_is_skip_dump(MemoryRegion *mr)
 
 uint8_t memory_region_is_logging(MemoryRegion *mr)
 {
-    return mr->dirty_log_mask;
+    uint8_t mask = mr->dirty_log_mask;
+    if (global_dirty_log) {
+        mask |= (1 << DIRTY_MEMORY_MIGRATION);
+    }
+    return mask;
 }
 
 bool memory_region_is_rom(MemoryRegion *mr)
-- 
2.3.3

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [Qemu-devel] [PATCH 10/22] ram_addr: tweaks to xen_modified_memory
  2015-03-26 17:38 [Qemu-devel] [PATCH 00/22] Dirty bitmap atomic access and optimizations Paolo Bonzini
                   ` (8 preceding siblings ...)
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 09/22] memory: return DIRTY_MEMORY_MIGRATION from memory_region_is_logging Paolo Bonzini
@ 2015-03-26 17:38 ` Paolo Bonzini
  2015-03-28 19:04   ` Stefano Stabellini
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 11/22] exec: simplify notdirty_mem_write Paolo Bonzini
                   ` (12 subsequent siblings)
  22 siblings, 1 reply; 39+ messages in thread
From: Paolo Bonzini @ 2015-03-26 17:38 UTC (permalink / raw)
  To: qemu-devel

Invoke xen_modified_memory from cpu_physical_memory_set_dirty_range_nocode;
it is akin to DIRTY_MEMORY_MIGRATION, so set it together with that bitmap.
The remaining call from invalidate_and_set_dirty's "else" branch will go
away soon.

Second, fix the second argument to the function in the
cpu_physical_memory_set_dirty_lebitmap call site.  That function is only used
by KVM, but it is better to be clean anyway.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 exec.c                  | 3 ++-
 include/exec/ram_addr.h | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/exec.c b/exec.c
index 8eb73fd..ffa57dd 100644
--- a/exec.c
+++ b/exec.c
@@ -2261,8 +2261,9 @@ static void invalidate_and_set_dirty(hwaddr addr,
     if (cpu_physical_memory_range_includes_clean(addr, length)) {
         tb_invalidate_phys_range(addr, addr + length, 0);
         cpu_physical_memory_set_dirty_range_nocode(addr, length);
+    } else {
+        xen_modified_memory(addr, length);
     }
-    xen_modified_memory(addr, length);
 }
 
 static int memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr)
diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
index ff558a4..7f6e928 100644
--- a/include/exec/ram_addr.h
+++ b/include/exec/ram_addr.h
@@ -112,6 +112,7 @@ static inline void cpu_physical_memory_set_dirty_range_nocode(ram_addr_t start,
     page = start >> TARGET_PAGE_BITS;
     bitmap_set(ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION], page, end - page);
     bitmap_set(ram_list.dirty_memory[DIRTY_MEMORY_VGA], page, end - page);
+    xen_modified_memory(start, length);
 }
 
 static inline void cpu_physical_memory_set_dirty_range(ram_addr_t start,
@@ -155,7 +156,7 @@ static inline void cpu_physical_memory_set_dirty_lebitmap(unsigned long *bitmap,
                 ram_list.dirty_memory[DIRTY_MEMORY_CODE][page + k] |= temp;
             }
         }
-        xen_modified_memory(start, pages);
+        xen_modified_memory(start, pages << TARGET_PAGE_BITS);
     } else {
         /*
          * bitmap-traveling is faster than memory-traveling (for addr...)
-- 
2.3.3

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [Qemu-devel] [PATCH 11/22] exec: simplify notdirty_mem_write
  2015-03-26 17:38 [Qemu-devel] [PATCH 00/22] Dirty bitmap atomic access and optimizations Paolo Bonzini
                   ` (9 preceding siblings ...)
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 10/22] ram_addr: tweaks to xen_modified_memory Paolo Bonzini
@ 2015-03-26 17:38 ` Paolo Bonzini
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 12/22] exec: use memory_region_is_logging to optimize dirty tracking Paolo Bonzini
                   ` (11 subsequent siblings)
  22 siblings, 0 replies; 39+ messages in thread
From: Paolo Bonzini @ 2015-03-26 17:38 UTC (permalink / raw)
  To: qemu-devel

The function has just set two dirty bits and invalidated code, thus
cpu_physical_memory_is_clean cannot return true here.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 exec.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/exec.c b/exec.c
index ffa57dd..56fd0f5 100644
--- a/exec.c
+++ b/exec.c
@@ -1810,6 +1810,7 @@ found:
 static void notdirty_mem_write(void *opaque, hwaddr ram_addr,
                                uint64_t val, unsigned size)
 {
+    CPUArchState *env = current_cpu->env_ptr;
     if (!cpu_physical_memory_get_dirty_flag(ram_addr, DIRTY_MEMORY_CODE)) {
         tb_invalidate_phys_page_fast(ram_addr, size);
     }
@@ -1827,12 +1828,7 @@ static void notdirty_mem_write(void *opaque, hwaddr ram_addr,
         abort();
     }
     cpu_physical_memory_set_dirty_range_nocode(ram_addr, size);
-    /* we remove the notdirty callback only if the code has been
-       flushed */
-    if (!cpu_physical_memory_is_clean(ram_addr)) {
-        CPUArchState *env = current_cpu->env_ptr;
-        tlb_set_dirty(env, current_cpu->mem_io_vaddr);
-    }
+    tlb_set_dirty(env, current_cpu->mem_io_vaddr);
 }
 
 static bool notdirty_mem_accepts(void *opaque, hwaddr addr,
-- 
2.3.3

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [Qemu-devel] [PATCH 12/22] exec: use memory_region_is_logging to optimize dirty tracking
  2015-03-26 17:38 [Qemu-devel] [PATCH 00/22] Dirty bitmap atomic access and optimizations Paolo Bonzini
                   ` (10 preceding siblings ...)
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 11/22] exec: simplify notdirty_mem_write Paolo Bonzini
@ 2015-03-26 17:38 ` Paolo Bonzini
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 13/22] exec: pass client mask to cpu_physical_memory_set_dirty_range Paolo Bonzini
                   ` (10 subsequent siblings)
  22 siblings, 0 replies; 39+ messages in thread
From: Paolo Bonzini @ 2015-03-26 17:38 UTC (permalink / raw)
  To: qemu-devel

memory_region_is_logging now returns the exact set of bitmaps that
have to be tracked.  Use it instead of the in_migration variable.

In the next patch, we will also use it to set only DIRTY_MEMORY_VGA
or DIRTY_MEMORY_MIGRATION if necessary.  As a result, fewer expensive
atomic operations will be required.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 exec.c | 62 ++++++++++++++++++++++----------------------------------------
 1 file changed, 22 insertions(+), 40 deletions(-)

diff --git a/exec.c b/exec.c
index 56fd0f5..ab2468b 100644
--- a/exec.c
+++ b/exec.c
@@ -59,8 +59,6 @@
 //#define DEBUG_SUBPAGE
 
 #if !defined(CONFIG_USER_ONLY)
-static bool in_migration;
-
 /* ram_list is read under rcu_read_lock()/rcu_read_unlock().  Writes
  * are protected by the ramlist lock.
  */
@@ -871,11 +869,6 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t length,
     }
 }
 
-static void cpu_physical_memory_set_dirty_tracking(bool enable)
-{
-    in_migration = enable;
-}
-
 /* Called from RCU critical section */
 hwaddr memory_region_section_get_iotlb(CPUState *cpu,
                                        MemoryRegionSection *section,
@@ -2137,22 +2130,6 @@ static void tcg_commit(MemoryListener *listener)
     }
 }
 
-static void core_log_global_start(MemoryListener *listener)
-{
-    cpu_physical_memory_set_dirty_tracking(true);
-}
-
-static void core_log_global_stop(MemoryListener *listener)
-{
-    cpu_physical_memory_set_dirty_tracking(false);
-}
-
-static MemoryListener core_memory_listener = {
-    .log_global_start = core_log_global_start,
-    .log_global_stop = core_log_global_stop,
-    .priority = 1,
-};
-
 void address_space_init_dispatch(AddressSpace *as)
 {
     as->dispatch = NULL;
@@ -2192,8 +2169,6 @@ static void memory_map_init(void)
     memory_region_init_io(system_io, NULL, &unassigned_io_ops, NULL, "io",
                           65536);
     address_space_init(&address_space_io, system_io, "I/O");
-
-    memory_listener_register(&core_memory_listener, &address_space_memory);
 }
 
 MemoryRegion *get_system_memory(void)
@@ -2251,12 +2226,18 @@ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
 
 #else
 
-static void invalidate_and_set_dirty(hwaddr addr,
+static void invalidate_and_set_dirty(MemoryRegion *mr, hwaddr addr,
                                      hwaddr length)
 {
     if (cpu_physical_memory_range_includes_clean(addr, length)) {
-        tb_invalidate_phys_range(addr, addr + length, 0);
-        cpu_physical_memory_set_dirty_range_nocode(addr, length);
+        dirty_log_mask = memory_region_is_logging(mr);
+        if (dirty_log_mask & (1 << DIRTY_MEMORY_CODE)) {
+            tb_invalidate_phys_range(addr, addr + length, 0);
+            dirty_log_mask &= ~(1 << DIRTY_MEMORY_CODE);
+        }
+        if (dirty_log_mask) {
+            cpu_physical_memory_set_dirty_range_nocode(addr, length);
+        }
     } else {
         xen_modified_memory(addr, length);
     }
@@ -2339,7 +2320,7 @@ bool address_space_rw(AddressSpace *as, hwaddr addr, uint8_t *buf,
                 /* RAM case */
                 ptr = qemu_get_ram_ptr(addr1);
                 memcpy(ptr, buf, l);
-                invalidate_and_set_dirty(addr1, l);
+                invalidate_and_set_dirty(mr, addr1, l);
             }
         } else {
             if (!memory_access_is_direct(mr, is_write)) {
@@ -2428,7 +2409,7 @@ static inline void cpu_physical_memory_write_rom_internal(AddressSpace *as,
             switch (type) {
             case WRITE_DATA:
                 memcpy(ptr, buf, l);
-                invalidate_and_set_dirty(addr1, l);
+                invalidate_and_set_dirty(mr, addr1, l);
                 break;
             case FLUSH_CACHE:
                 flush_icache_range((uintptr_t)ptr, (uintptr_t)ptr + l);
@@ -2644,7 +2625,7 @@ void address_space_unmap(AddressSpace *as, void *buffer, hwaddr len,
         mr = qemu_ram_addr_from_host(buffer, &addr1);
         assert(mr != NULL);
         if (is_write) {
-            invalidate_and_set_dirty(addr1, access_len);
+            invalidate_and_set_dirty(mr, addr1, access_len);
         }
         if (xen_enabled()) {
             xen_invalidate_map_cache_entry(buffer);
@@ -2868,6 +2849,7 @@ void stl_phys_notdirty(AddressSpace *as, hwaddr addr, uint32_t val)
     MemoryRegion *mr;
     hwaddr l = 4;
     hwaddr addr1;
+    uint8_t dirty_log_mask;
 
     mr = address_space_translate(as, addr, &addr1, &l,
                                  true);
@@ -2878,13 +2860,13 @@ void stl_phys_notdirty(AddressSpace *as, hwaddr addr, uint32_t val)
         ptr = qemu_get_ram_ptr(addr1);
         stl_p(ptr, val);
 
-        if (unlikely(in_migration)) {
-            if (cpu_physical_memory_is_clean(addr1)) {
-                /* invalidate code */
-                tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
-                /* set dirty bit */
-                cpu_physical_memory_set_dirty_range_nocode(addr1, 4);
-            }
+        dirty_log_mask = memory_region_is_logging(mr);
+        if (dirty_log_mask & (1 << DIRTY_MEMORY_CODE)) {
+            tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
+            dirty_log_mask &= ~(1 << DIRTY_MEMORY_CODE);
+        }
+        if (dirty_log_mask) {
+            cpu_physical_memory_set_dirty_range_nocode(addr1, 4);
         }
     }
 }
@@ -2927,7 +2909,7 @@ static inline void stl_phys_internal(AddressSpace *as,
             stl_p(ptr, val);
             break;
         }
-        invalidate_and_set_dirty(addr1, 4);
+        invalidate_and_set_dirty(mr, addr1, 4);
     }
 }
 
@@ -2990,7 +2972,7 @@ static inline void stw_phys_internal(AddressSpace *as,
             stw_p(ptr, val);
             break;
         }
-        invalidate_and_set_dirty(addr1, 2);
+        invalidate_and_set_dirty(mr, addr1, 2);
     }
 }
 
-- 
2.3.3

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [Qemu-devel] [PATCH 13/22] exec: pass client mask to cpu_physical_memory_set_dirty_range
  2015-03-26 17:38 [Qemu-devel] [PATCH 00/22] Dirty bitmap atomic access and optimizations Paolo Bonzini
                   ` (11 preceding siblings ...)
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 12/22] exec: use memory_region_is_logging to optimize dirty tracking Paolo Bonzini
@ 2015-03-26 17:38 ` Paolo Bonzini
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 14/22] exec: only check relevant bitmaps for cleanliness Paolo Bonzini
                   ` (9 subsequent siblings)
  22 siblings, 0 replies; 39+ messages in thread
From: Paolo Bonzini @ 2015-03-26 17:38 UTC (permalink / raw)
  To: qemu-devel

This cuts in half the cost of bitmap operations (which will become more
expensive when made atomic) during migration on non-VRAM regions.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 exec.c                  | 23 +++++++++++++----------
 include/exec/ram_addr.h | 33 ++++++++++++++++-----------------
 memory.c                |  3 ++-
 3 files changed, 31 insertions(+), 28 deletions(-)

diff --git a/exec.c b/exec.c
index ab2468b..94b7644 100644
--- a/exec.c
+++ b/exec.c
@@ -1356,7 +1356,8 @@ int qemu_ram_resize(ram_addr_t base, ram_addr_t newsize, Error **errp)
 
     cpu_physical_memory_clear_dirty_range(block->offset, block->used_length);
     block->used_length = newsize;
-    cpu_physical_memory_set_dirty_range(block->offset, block->used_length);
+    cpu_physical_memory_set_dirty_range(block->offset, block->used_length,
+                                        DIRTY_CLIENT_ALL);
     memory_region_set_size(block->mr, newsize);
     if (block->resized) {
         block->resized(block->idstr, newsize, block->host);
@@ -1430,7 +1431,8 @@ static ram_addr_t ram_block_add(RAMBlock *new_block, Error **errp)
        }
     }
     cpu_physical_memory_set_dirty_range(new_block->offset,
-                                        new_block->used_length);
+                                        new_block->used_length,
+                                        DIRTY_CLIENT_ALL);
 
     if (new_block->host) {
         qemu_ram_setup_dump(new_block->host, new_block->max_length);
@@ -1820,7 +1822,12 @@ static void notdirty_mem_write(void *opaque, hwaddr ram_addr,
     default:
         abort();
     }
-    cpu_physical_memory_set_dirty_range_nocode(ram_addr, size);
+
+    /* Set both VGA and migration bits for simplicity and to remove
+     * the notdirty callback faster.
+     */
+    cpu_physical_memory_set_dirty_range(ram_addr, size,
+                                        DIRTY_CLIENT_NOCODE);
     tlb_set_dirty(env, current_cpu->mem_io_vaddr);
 }
 
@@ -2230,14 +2237,12 @@ static void invalidate_and_set_dirty(MemoryRegion *mr, hwaddr addr,
                                      hwaddr length)
 {
     if (cpu_physical_memory_range_includes_clean(addr, length)) {
-        dirty_log_mask = memory_region_is_logging(mr);
+        uint8_t dirty_log_mask = memory_region_is_logging(mr);
         if (dirty_log_mask & (1 << DIRTY_MEMORY_CODE)) {
             tb_invalidate_phys_range(addr, addr + length, 0);
             dirty_log_mask &= ~(1 << DIRTY_MEMORY_CODE);
         }
-        if (dirty_log_mask) {
-            cpu_physical_memory_set_dirty_range_nocode(addr, length);
-        }
+        cpu_physical_memory_set_dirty_range(addr, length, dirty_log_mask);
     } else {
         xen_modified_memory(addr, length);
     }
@@ -2865,9 +2870,7 @@ void stl_phys_notdirty(AddressSpace *as, hwaddr addr, uint32_t val)
             tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
             dirty_log_mask &= ~(1 << DIRTY_MEMORY_CODE);
         }
-        if (dirty_log_mask) {
-            cpu_physical_memory_set_dirty_range_nocode(addr1, 4);
-        }
+        cpu_physical_memory_set_dirty_range(addr1, 4, dirty_log_mask);
     }
 }
 
diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
index 7f6e928..6c3b74e 100644
--- a/include/exec/ram_addr.h
+++ b/include/exec/ram_addr.h
@@ -41,6 +41,9 @@ void qemu_ram_free_from_ptr(ram_addr_t addr);
 
 int qemu_ram_resize(ram_addr_t base, ram_addr_t newsize, Error **errp);
 
+#define DIRTY_CLIENT_ALL	((1 << DIRTY_MEMORY_NUM) - 1)
+#define DIRTY_CLIENT_NOCODE	(DIRTY_CLIENT_ALL & ~ (1 << DIRTY_MEMORY_CODE))
+
 static inline bool cpu_physical_memory_get_dirty(ram_addr_t start,
                                                  ram_addr_t length,
                                                  unsigned client)
@@ -103,28 +106,23 @@ static inline void cpu_physical_memory_set_dirty_flag(ram_addr_t addr,
     set_bit(addr >> TARGET_PAGE_BITS, ram_list.dirty_memory[client]);
 }
 
-static inline void cpu_physical_memory_set_dirty_range_nocode(ram_addr_t start,
-                                                              ram_addr_t length)
-{
-    unsigned long end, page;
-
-    end = TARGET_PAGE_ALIGN(start + length) >> TARGET_PAGE_BITS;
-    page = start >> TARGET_PAGE_BITS;
-    bitmap_set(ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION], page, end - page);
-    bitmap_set(ram_list.dirty_memory[DIRTY_MEMORY_VGA], page, end - page);
-    xen_modified_memory(start, length);
-}
-
 static inline void cpu_physical_memory_set_dirty_range(ram_addr_t start,
-                                                       ram_addr_t length)
+                                                       ram_addr_t length,
+                                                       uint8_t mask)
 {
     unsigned long end, page;
 
     end = TARGET_PAGE_ALIGN(start + length) >> TARGET_PAGE_BITS;
     page = start >> TARGET_PAGE_BITS;
-    bitmap_set(ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION], page, end - page);
-    bitmap_set(ram_list.dirty_memory[DIRTY_MEMORY_VGA], page, end - page);
-    bitmap_set(ram_list.dirty_memory[DIRTY_MEMORY_CODE], page, end - page);
+    if (likely(mask & DIRTY_MEMORY_MIGRATION)) {
+        bitmap_set(ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION], page, end - page);
+    }
+    if (unlikely(mask & DIRTY_MEMORY_VGA)) {
+        bitmap_set(ram_list.dirty_memory[DIRTY_MEMORY_VGA], page, end - page);
+    }
+    if (unlikely(mask & DIRTY_MEMORY_CODE)) {
+        bitmap_set(ram_list.dirty_memory[DIRTY_MEMORY_CODE], page, end - page);
+    }
     xen_modified_memory(start, length);
 }
 
@@ -172,7 +170,8 @@ static inline void cpu_physical_memory_set_dirty_lebitmap(unsigned long *bitmap,
                     addr = page_number * TARGET_PAGE_SIZE;
                     ram_addr = start + addr;
                     cpu_physical_memory_set_dirty_range(ram_addr,
-                                       TARGET_PAGE_SIZE * hpratio);
+                                       TARGET_PAGE_SIZE * hpratio,
+                                       DIRTY_CLIENT_ALL);
                 } while (c != 0);
             }
         }
diff --git a/memory.c b/memory.c
index 76da05b..6061b27 100644
--- a/memory.c
+++ b/memory.c
@@ -1380,7 +1380,8 @@ void memory_region_set_dirty(MemoryRegion *mr, hwaddr addr,
                              hwaddr size)
 {
     assert(mr->terminates);
-    cpu_physical_memory_set_dirty_range(mr->ram_addr + addr, size);
+    cpu_physical_memory_set_dirty_range(mr->ram_addr + addr, size,
+                                        memory_region_is_logging(mr));
 }
 
 bool memory_region_test_and_clear_dirty(MemoryRegion *mr, hwaddr addr,
-- 
2.3.3

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [Qemu-devel] [PATCH 14/22] exec: only check relevant bitmaps for cleanliness
  2015-03-26 17:38 [Qemu-devel] [PATCH 00/22] Dirty bitmap atomic access and optimizations Paolo Bonzini
                   ` (12 preceding siblings ...)
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 13/22] exec: pass client mask to cpu_physical_memory_set_dirty_range Paolo Bonzini
@ 2015-03-26 17:38 ` Paolo Bonzini
  2015-03-27  6:10   ` Fam Zheng
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 15/22] memory: do not touch code dirty bitmap unless TCG is enabled Paolo Bonzini
                   ` (8 subsequent siblings)
  22 siblings, 1 reply; 39+ messages in thread
From: Paolo Bonzini @ 2015-03-26 17:38 UTC (permalink / raw)
  To: qemu-devel

Most of the time, not all bitmaps have to be marked as dirty;
do not do anything if the interesting ones are already dirty.
Previously, any clean bitmap would have cause all the bitmaps to be
marked dirty.

In fact, unless running TCG most of the time bitmap operations
are not done at all because memory_region_is_logging returns
zero.  In this case, skip cpu_physical_memory_range_includes_clean
as well.

With this patch, cpu_physical_memory_set_dirty_range is called
unconditionally, so there need not be anymore a separate call to
xen_modified_memory.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 exec.c                  | 18 +++++++++---------
 include/exec/ram_addr.h | 19 +++++++++++++------
 2 files changed, 22 insertions(+), 15 deletions(-)

diff --git a/exec.c b/exec.c
index 94b7644..83c58ff 100644
--- a/exec.c
+++ b/exec.c
@@ -2236,16 +2236,16 @@ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
 static void invalidate_and_set_dirty(MemoryRegion *mr, hwaddr addr,
                                      hwaddr length)
 {
-    if (cpu_physical_memory_range_includes_clean(addr, length)) {
-        uint8_t dirty_log_mask = memory_region_is_logging(mr);
-        if (dirty_log_mask & (1 << DIRTY_MEMORY_CODE)) {
-            tb_invalidate_phys_range(addr, addr + length, 0);
-            dirty_log_mask &= ~(1 << DIRTY_MEMORY_CODE);
-        }
-        cpu_physical_memory_set_dirty_range(addr, length, dirty_log_mask);
-    } else {
-        xen_modified_memory(addr, length);
+    uint8_t dirty_log_mask = memory_region_is_logging(mr);
+    if (dirty_log_mask &&
+        !cpu_physical_memory_range_includes_clean(addr, length, dirty_log_mask)) {
+        dirty_log_mask = 0;
+    }
+    if (dirty_log_mask & (1 << DIRTY_MEMORY_CODE)) {
+        tb_invalidate_phys_range(addr, addr + length, 0);
+        dirty_log_mask &= ~(1 << DIRTY_MEMORY_CODE);
     }
+    cpu_physical_memory_set_dirty_range(addr, length, dirty_log_mask);
 }
 
 static int memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr)
diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
index 6c3b74e..b408408 100644
--- a/include/exec/ram_addr.h
+++ b/include/exec/ram_addr.h
@@ -90,13 +90,20 @@ static inline bool cpu_physical_memory_is_clean(ram_addr_t addr)
 }
 
 static inline bool cpu_physical_memory_range_includes_clean(ram_addr_t start,
-                                                            ram_addr_t length)
+                                                            ram_addr_t length,
+                                                            uint8_t mask)
 {
-    bool vga = cpu_physical_memory_get_clean(start, length, DIRTY_MEMORY_VGA);
-    bool code = cpu_physical_memory_get_clean(start, length, DIRTY_MEMORY_CODE);
-    bool migration =
-        cpu_physical_memory_get_clean(start, length, DIRTY_MEMORY_MIGRATION);
-    return vga || code || migration;
+    bool clean = false;
+    if (mask & (1 << DIRTY_MEMORY_VGA)) {
+        clean = cpu_physical_memory_get_clean(start, length, DIRTY_MEMORY_VGA);
+    }
+    if (!clean && (mask & (1 << DIRTY_MEMORY_CODE))) {
+        clean = cpu_physical_memory_get_clean(start, length, DIRTY_MEMORY_CODE);
+    }
+    if (!clean && (mask & (1 << DIRTY_MEMORY_MIGRATION))) {
+        clean = cpu_physical_memory_get_clean(start, length, DIRTY_MEMORY_MIGRATION);
+    }
+    return clean;
 }
 
 static inline void cpu_physical_memory_set_dirty_flag(ram_addr_t addr,
-- 
2.3.3

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [Qemu-devel] [PATCH 15/22] memory: do not touch code dirty bitmap unless TCG is enabled
  2015-03-26 17:38 [Qemu-devel] [PATCH 00/22] Dirty bitmap atomic access and optimizations Paolo Bonzini
                   ` (13 preceding siblings ...)
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 14/22] exec: only check relevant bitmaps for cleanliness Paolo Bonzini
@ 2015-03-26 17:38 ` Paolo Bonzini
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 16/22] bitmap: add atomic set functions Paolo Bonzini
                   ` (7 subsequent siblings)
  22 siblings, 0 replies; 39+ messages in thread
From: Paolo Bonzini @ 2015-03-26 17:38 UTC (permalink / raw)
  To: qemu-devel

cpu_physical_memory_set_dirty_lebitmap unconditionally syncs the
DIRTY_MEMORY_CODE bitmap.  This however is unused unless TCG is
enabled.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 include/exec/ram_addr.h | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
index b408408..675263c 100644
--- a/include/exec/ram_addr.h
+++ b/include/exec/ram_addr.h
@@ -158,11 +158,14 @@ static inline void cpu_physical_memory_set_dirty_lebitmap(unsigned long *bitmap,
 
                 ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION][page + k] |= temp;
                 ram_list.dirty_memory[DIRTY_MEMORY_VGA][page + k] |= temp;
-                ram_list.dirty_memory[DIRTY_MEMORY_CODE][page + k] |= temp;
+                if (tcg_enabled()) {
+                    ram_list.dirty_memory[DIRTY_MEMORY_CODE][page + k] |= temp;
+                }
             }
         }
         xen_modified_memory(start, pages << TARGET_PAGE_BITS);
     } else {
+        uint8_t clients = tcg_enabled() ? DIRTY_CLIENT_ALL : DIRTY_CLIENT_NOCODE;
         /*
          * bitmap-traveling is faster than memory-traveling (for addr...)
          * especially when most of the memory is not dirty.
@@ -177,8 +180,7 @@ static inline void cpu_physical_memory_set_dirty_lebitmap(unsigned long *bitmap,
                     addr = page_number * TARGET_PAGE_SIZE;
                     ram_addr = start + addr;
                     cpu_physical_memory_set_dirty_range(ram_addr,
-                                       TARGET_PAGE_SIZE * hpratio,
-                                       DIRTY_CLIENT_ALL);
+                                       TARGET_PAGE_SIZE * hpratio, clients);
                 } while (c != 0);
             }
         }
-- 
2.3.3

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [Qemu-devel] [PATCH 16/22] bitmap: add atomic set functions
  2015-03-26 17:38 [Qemu-devel] [PATCH 00/22] Dirty bitmap atomic access and optimizations Paolo Bonzini
                   ` (14 preceding siblings ...)
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 15/22] memory: do not touch code dirty bitmap unless TCG is enabled Paolo Bonzini
@ 2015-03-26 17:38 ` Paolo Bonzini
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 17/22] bitmap: add atomic test and clear Paolo Bonzini
                   ` (6 subsequent siblings)
  22 siblings, 0 replies; 39+ messages in thread
From: Paolo Bonzini @ 2015-03-26 17:38 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stefan Hajnoczi

From: Stefan Hajnoczi <stefanha@redhat.com>

Use atomic_or() for atomic bitmaps where several threads may set bits at
the same time.  This avoids the race condition between threads loading
an element, bitwise ORing, and then storing the element.

When setting all bits in a word we can avoid atomic ops and instead just
use an smp_mb() at the end.

Most bitmap users don't need atomicity so introduce new functions.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Message-Id: <1417519399-3166-2-git-send-email-stefanha@redhat.com>
[Avoid barrier in the single word case, use full barrier instead of write.
 - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 include/qemu/bitmap.h |  2 ++
 include/qemu/bitops.h | 14 ++++++++++++++
 util/bitmap.c         | 35 +++++++++++++++++++++++++++++++++++
 3 files changed, 51 insertions(+)

diff --git a/include/qemu/bitmap.h b/include/qemu/bitmap.h
index f0273c9..3e0a4f3 100644
--- a/include/qemu/bitmap.h
+++ b/include/qemu/bitmap.h
@@ -39,6 +39,7 @@
  * bitmap_empty(src, nbits)			Are all bits zero in *src?
  * bitmap_full(src, nbits)			Are all bits set in *src?
  * bitmap_set(dst, pos, nbits)			Set specified bit area
+ * bitmap_set_atomic(dst, pos, nbits)   Set specified bit area with atomic ops
  * bitmap_clear(dst, pos, nbits)		Clear specified bit area
  * bitmap_find_next_zero_area(buf, len, pos, n, mask)	Find bit free area
  */
@@ -226,6 +227,7 @@ static inline int bitmap_intersects(const unsigned long *src1,
 }
 
 void bitmap_set(unsigned long *map, long i, long len);
+void bitmap_set_atomic(unsigned long *map, long i, long len);
 void bitmap_clear(unsigned long *map, long start, long nr);
 unsigned long bitmap_find_next_zero_area(unsigned long *map,
                                          unsigned long size,
diff --git a/include/qemu/bitops.h b/include/qemu/bitops.h
index 90ca8df..95f98fb 100644
--- a/include/qemu/bitops.h
+++ b/include/qemu/bitops.h
@@ -16,6 +16,7 @@
 #include <assert.h>
 
 #include "host-utils.h"
+#include "atomic.h"
 
 #define BITS_PER_BYTE           CHAR_BIT
 #define BITS_PER_LONG           (sizeof (unsigned long) * BITS_PER_BYTE)
@@ -39,6 +40,19 @@ static inline void set_bit(long nr, unsigned long *addr)
 }
 
 /**
+ * set_bit_atomic - Set a bit in memory atomically
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ */
+static inline void set_bit_atomic(long nr, unsigned long *addr)
+{
+    unsigned long mask = BIT_MASK(nr);
+    unsigned long *p = addr + BIT_WORD(nr);
+
+    atomic_or(p, mask);
+}
+
+/**
  * clear_bit - Clears a bit in memory
  * @nr: Bit to clear
  * @addr: Address to start counting from
diff --git a/util/bitmap.c b/util/bitmap.c
index 9c6bb52..e4957da 100644
--- a/util/bitmap.c
+++ b/util/bitmap.c
@@ -11,6 +11,7 @@
 
 #include "qemu/bitops.h"
 #include "qemu/bitmap.h"
+#include "qemu/atomic.h"
 
 /*
  * bitmaps provide an array of bits, implemented using an an
@@ -177,6 +178,40 @@ void bitmap_set(unsigned long *map, long start, long nr)
     }
 }
 
+void bitmap_set_atomic(unsigned long *map, long start, long nr)
+{
+    unsigned long *p = map + BIT_WORD(start);
+    const long size = start + nr;
+    int bits_to_set = BITS_PER_LONG - (start % BITS_PER_LONG);
+    unsigned long mask_to_set = BITMAP_FIRST_WORD_MASK(start);
+
+    /* First word */
+    if (nr - bits_to_set > 0) {
+        atomic_or(p, mask_to_set);
+        nr -= bits_to_set;
+        bits_to_set = BITS_PER_LONG;
+        p++;
+    }
+
+    /* Full words */
+    while (nr - bits_to_set >= 0) {
+        *p = ~0UL;
+        nr -= bits_to_set;
+        p++;
+    }
+
+    /* Last word */
+    if (nr) {
+        mask_to_set &= BITMAP_LAST_WORD_MASK(size);
+        atomic_or(p, mask_to_set);
+    } else {
+        /* If we avoided the full barrier in atomic_or(), but issue a
+         * barrier to account for the assignments in the while loop.
+         */
+        smp_mb();
+    }
+}
+
 void bitmap_clear(unsigned long *map, long start, long nr)
 {
     unsigned long *p = map + BIT_WORD(start);
-- 
2.3.3

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [Qemu-devel] [PATCH 17/22] bitmap: add atomic test and clear
  2015-03-26 17:38 [Qemu-devel] [PATCH 00/22] Dirty bitmap atomic access and optimizations Paolo Bonzini
                   ` (15 preceding siblings ...)
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 16/22] bitmap: add atomic set functions Paolo Bonzini
@ 2015-03-26 17:38 ` Paolo Bonzini
  2015-03-27  6:37   ` Fam Zheng
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 18/22] memory: use atomic ops for setting dirty memory bits Paolo Bonzini
                   ` (5 subsequent siblings)
  22 siblings, 1 reply; 39+ messages in thread
From: Paolo Bonzini @ 2015-03-26 17:38 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stefan Hajnoczi

From: Stefan Hajnoczi <stefanha@redhat.com>

The new bitmap_test_and_clear_atomic() function clears a range and
returns whether or not the bits were set.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Message-Id: <1417519399-3166-3-git-send-email-stefanha@redhat.com>
[Test before xchg; then a full barrier is needed at the end just like
 in the previous patch.  The barrier can be avoided if we did at least
 one xchg.  - Paolo]

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 include/qemu/bitmap.h |  2 ++
 util/bitmap.c         | 43 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 45 insertions(+)

diff --git a/include/qemu/bitmap.h b/include/qemu/bitmap.h
index 3e0a4f3..86dd9cd 100644
--- a/include/qemu/bitmap.h
+++ b/include/qemu/bitmap.h
@@ -41,6 +41,7 @@
  * bitmap_set(dst, pos, nbits)			Set specified bit area
  * bitmap_set_atomic(dst, pos, nbits)   Set specified bit area with atomic ops
  * bitmap_clear(dst, pos, nbits)		Clear specified bit area
+ * bitmap_test_and_clear_atomic(dst, pos, nbits)    Test and clear area
  * bitmap_find_next_zero_area(buf, len, pos, n, mask)	Find bit free area
  */
 
@@ -229,6 +230,7 @@ static inline int bitmap_intersects(const unsigned long *src1,
 void bitmap_set(unsigned long *map, long i, long len);
 void bitmap_set_atomic(unsigned long *map, long i, long len);
 void bitmap_clear(unsigned long *map, long start, long nr);
+bool bitmap_test_and_clear_atomic(unsigned long *map, long start, long nr);
 unsigned long bitmap_find_next_zero_area(unsigned long *map,
                                          unsigned long size,
                                          unsigned long start,
diff --git a/util/bitmap.c b/util/bitmap.c
index e4957da..570758a 100644
--- a/util/bitmap.c
+++ b/util/bitmap.c
@@ -232,6 +232,49 @@ void bitmap_clear(unsigned long *map, long start, long nr)
     }
 }
 
+bool bitmap_test_and_clear_atomic(unsigned long *map, long start, long nr)
+{
+    unsigned long *p = map + BIT_WORD(start);
+    const long size = start + nr;
+    int bits_to_clear = BITS_PER_LONG - (start % BITS_PER_LONG);
+    unsigned long mask_to_clear = BITMAP_FIRST_WORD_MASK(start);
+    unsigned long dirty = 0;
+    unsigned long old_bits;
+
+    /* First word */
+    if (nr - bits_to_clear > 0) {
+        old_bits = atomic_fetch_and(p, ~mask_to_clear);
+        dirty |= old_bits & mask_to_clear;
+        nr -= bits_to_clear;
+        bits_to_clear = BITS_PER_LONG;
+        mask_to_clear = ~0UL;
+        p++;
+    }
+
+    /* Full words */
+    while (nr - bits_to_clear >= 0) {
+        if (*p) {
+            old_bits = atomic_xchg(p, 0);
+            dirty |= old_bits;
+        }
+        nr -= bits_to_clear;
+        p++;
+    }
+
+    /* Last word */
+    if (nr) {
+        mask_to_clear &= BITMAP_LAST_WORD_MASK(size);
+        old_bits = atomic_fetch_and(p, ~mask_to_clear);
+        dirty |= old_bits & mask_to_clear;
+    } else {
+        if (!dirty) {
+            smp_mb();
+        }
+    }
+
+    return dirty;
+}
+
 #define ALIGN_MASK(x,mask)      (((x)+(mask))&~(mask))
 
 /**
-- 
2.3.3

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [Qemu-devel] [PATCH 18/22] memory: use atomic ops for setting dirty memory bits
  2015-03-26 17:38 [Qemu-devel] [PATCH 00/22] Dirty bitmap atomic access and optimizations Paolo Bonzini
                   ` (16 preceding siblings ...)
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 17/22] bitmap: add atomic test and clear Paolo Bonzini
@ 2015-03-26 17:38 ` Paolo Bonzini
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 19/22] migration: move dirty bitmap sync to ram_addr.h Paolo Bonzini
                   ` (4 subsequent siblings)
  22 siblings, 0 replies; 39+ messages in thread
From: Paolo Bonzini @ 2015-03-26 17:38 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stefan Hajnoczi

From: Stefan Hajnoczi <stefanha@redhat.com>

Use set_bit_atomic() and bitmap_set_atomic() so that multiple threads
can dirty memory without race conditions.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Message-Id: <1417519399-3166-4-git-send-email-stefanha@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 include/exec/ram_addr.h | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
index 675263c..bcfa64f 100644
--- a/include/exec/ram_addr.h
+++ b/include/exec/ram_addr.h
@@ -110,7 +110,7 @@ static inline void cpu_physical_memory_set_dirty_flag(ram_addr_t addr,
                                                       unsigned client)
 {
     assert(client < DIRTY_MEMORY_NUM);
-    set_bit(addr >> TARGET_PAGE_BITS, ram_list.dirty_memory[client]);
+    set_bit_atomic(addr >> TARGET_PAGE_BITS, ram_list.dirty_memory[client]);
 }
 
 static inline void cpu_physical_memory_set_dirty_range(ram_addr_t start,
@@ -118,17 +118,18 @@ static inline void cpu_physical_memory_set_dirty_range(ram_addr_t start,
                                                        uint8_t mask)
 {
     unsigned long end, page;
+    unsigned long **d = ram_list.dirty_memory;
 
     end = TARGET_PAGE_ALIGN(start + length) >> TARGET_PAGE_BITS;
     page = start >> TARGET_PAGE_BITS;
     if (likely(mask & DIRTY_MEMORY_MIGRATION)) {
-        bitmap_set(ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION], page, end - page);
+        bitmap_set_atomic(d[DIRTY_MEMORY_MIGRATION], page, end - page);
     }
     if (unlikely(mask & DIRTY_MEMORY_VGA)) {
-        bitmap_set(ram_list.dirty_memory[DIRTY_MEMORY_VGA], page, end - page);
+        bitmap_set_atomic(d[DIRTY_MEMORY_VGA], page, end - page);
     }
     if (unlikely(mask & DIRTY_MEMORY_CODE)) {
-        bitmap_set(ram_list.dirty_memory[DIRTY_MEMORY_CODE], page, end - page);
+        bitmap_set_atomic(d[DIRTY_MEMORY_CODE], page, end - page);
     }
     xen_modified_memory(start, length);
 }
@@ -155,11 +156,12 @@ static inline void cpu_physical_memory_set_dirty_lebitmap(unsigned long *bitmap,
         for (k = 0; k < nr; k++) {
             if (bitmap[k]) {
                 unsigned long temp = leul_to_cpu(bitmap[k]);
+                unsigned long **d = ram_list.dirty_memory;
 
-                ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION][page + k] |= temp;
-                ram_list.dirty_memory[DIRTY_MEMORY_VGA][page + k] |= temp;
+                atomic_or(&d[DIRTY_MEMORY_MIGRATION][page + k], temp);
+                atomic_or(&d[DIRTY_MEMORY_VGA][page + k], temp);
                 if (tcg_enabled()) {
-                    ram_list.dirty_memory[DIRTY_MEMORY_CODE][page + k] |= temp;
+                    atomic_or(&d[DIRTY_MEMORY_CODE][page + k], temp);
                 }
             }
         }
-- 
2.3.3

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [Qemu-devel] [PATCH 19/22] migration: move dirty bitmap sync to ram_addr.h
  2015-03-26 17:38 [Qemu-devel] [PATCH 00/22] Dirty bitmap atomic access and optimizations Paolo Bonzini
                   ` (17 preceding siblings ...)
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 18/22] memory: use atomic ops for setting dirty memory bits Paolo Bonzini
@ 2015-03-26 17:38 ` Paolo Bonzini
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 20/22] memory: replace cpu_physical_memory_reset_dirty() with test-and-clear Paolo Bonzini
                   ` (3 subsequent siblings)
  22 siblings, 0 replies; 39+ messages in thread
From: Paolo Bonzini @ 2015-03-26 17:38 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stefan Hajnoczi

From: Stefan Hajnoczi <stefanha@redhat.com>

The dirty memory bitmap is managed by ram_addr.h and copied to
migration_bitmap[] periodically during live migration.

Move the code to sync the bitmap to ram_addr.h where related code lives.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Message-Id: <1417519399-3166-5-git-send-email-stefanha@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 arch_init.c             | 46 ++--------------------------------------------
 include/exec/ram_addr.h | 44 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 46 insertions(+), 44 deletions(-)

diff --git a/arch_init.c b/arch_init.c
index fcfa328..75bba49 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -472,52 +472,10 @@ ram_addr_t migration_bitmap_find_and_reset_dirty(MemoryRegion *mr,
     return (next - base) << TARGET_PAGE_BITS;
 }
 
-static inline bool migration_bitmap_set_dirty(ram_addr_t addr)
-{
-    bool ret;
-    int nr = addr >> TARGET_PAGE_BITS;
-
-    ret = test_and_set_bit(nr, migration_bitmap);
-
-    if (!ret) {
-        migration_dirty_pages++;
-    }
-    return ret;
-}
-
 static void migration_bitmap_sync_range(ram_addr_t start, ram_addr_t length)
 {
-    ram_addr_t addr;
-    unsigned long page = BIT_WORD(start >> TARGET_PAGE_BITS);
-
-    /* start address is aligned at the start of a word? */
-    if (((page * BITS_PER_LONG) << TARGET_PAGE_BITS) == start) {
-        int k;
-        int nr = BITS_TO_LONGS(length >> TARGET_PAGE_BITS);
-        unsigned long *src = ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION];
-
-        for (k = page; k < page + nr; k++) {
-            if (src[k]) {
-                unsigned long new_dirty;
-                new_dirty = ~migration_bitmap[k];
-                migration_bitmap[k] |= src[k];
-                new_dirty &= src[k];
-                migration_dirty_pages += ctpopl(new_dirty);
-                src[k] = 0;
-            }
-        }
-    } else {
-        for (addr = 0; addr < length; addr += TARGET_PAGE_SIZE) {
-            if (cpu_physical_memory_get_dirty(start + addr,
-                                              TARGET_PAGE_SIZE,
-                                              DIRTY_MEMORY_MIGRATION)) {
-                cpu_physical_memory_reset_dirty(start + addr,
-                                                TARGET_PAGE_SIZE,
-                                                DIRTY_MEMORY_MIGRATION);
-                migration_bitmap_set_dirty(start + addr);
-            }
-        }
-    }
+    migration_dirty_pages +=
+        cpu_physical_memory_sync_dirty_bitmap(migration_bitmap, start, length);
 }
 
 
diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
index bcfa64f..a68bde2 100644
--- a/include/exec/ram_addr.h
+++ b/include/exec/ram_addr.h
@@ -214,5 +214,49 @@ static inline void cpu_physical_memory_clear_dirty_range(ram_addr_t start,
 void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t length,
                                      unsigned client);
 
+static inline
+uint64_t cpu_physical_memory_sync_dirty_bitmap(unsigned long *dest,
+                                               ram_addr_t start,
+                                               ram_addr_t length)
+{
+    ram_addr_t addr;
+    unsigned long page = BIT_WORD(start >> TARGET_PAGE_BITS);
+    uint64_t num_dirty = 0;
+
+    /* start address is aligned at the start of a word? */
+    if (((page * BITS_PER_LONG) << TARGET_PAGE_BITS) == start) {
+        int k;
+        int nr = BITS_TO_LONGS(length >> TARGET_PAGE_BITS);
+        unsigned long *src = ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION];
+
+        for (k = page; k < page + nr; k++) {
+            if (src[k]) {
+                unsigned long new_dirty;
+                new_dirty = ~dest[k];
+                dest[k] |= src[k];
+                new_dirty &= src[k];
+                num_dirty += ctpopl(new_dirty);
+                src[k] = 0;
+            }
+        }
+    } else {
+        for (addr = 0; addr < length; addr += TARGET_PAGE_SIZE) {
+            if (cpu_physical_memory_get_dirty(start + addr,
+                                              TARGET_PAGE_SIZE,
+                                              DIRTY_MEMORY_MIGRATION)) {
+                cpu_physical_memory_reset_dirty(start + addr,
+                                                TARGET_PAGE_SIZE,
+                                                DIRTY_MEMORY_MIGRATION);
+                long k = (start + addr) >> TARGET_PAGE_BITS;
+                if (!test_and_set_bit(k, dest)) {
+                    num_dirty++;
+                }
+            }
+        }
+    }
+
+    return num_dirty;
+}
+
 #endif
 #endif
-- 
2.3.3

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [Qemu-devel] [PATCH 20/22] memory: replace cpu_physical_memory_reset_dirty() with test-and-clear
  2015-03-26 17:38 [Qemu-devel] [PATCH 00/22] Dirty bitmap atomic access and optimizations Paolo Bonzini
                   ` (18 preceding siblings ...)
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 19/22] migration: move dirty bitmap sync to ram_addr.h Paolo Bonzini
@ 2015-03-26 17:38 ` Paolo Bonzini
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 21/22] memory: make cpu_physical_memory_sync_dirty_bitmap() fully atomic Paolo Bonzini
                   ` (2 subsequent siblings)
  22 siblings, 0 replies; 39+ messages in thread
From: Paolo Bonzini @ 2015-03-26 17:38 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stefan Hajnoczi

From: Stefan Hajnoczi <stefanha@redhat.com>

The cpu_physical_memory_reset_dirty() function is sometimes used
together with cpu_physical_memory_get_dirty().  This is not atomic since
two separate accesses to the dirty memory bitmap are made.

Turn cpu_physical_memory_reset_dirty() and
cpu_physical_memory_clear_dirty_range_type() into the atomic
cpu_physical_memory_test_and_clear_dirty().

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Message-Id: <1417519399-3166-6-git-send-email-stefanha@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 cputlb.c                |  4 ++--
 exec.c                  | 23 +++++++++++++++++------
 include/exec/ram_addr.h | 33 ++++++++++-----------------------
 memory.c                | 11 ++++-------
 4 files changed, 33 insertions(+), 38 deletions(-)

diff --git a/cputlb.c b/cputlb.c
index 38f2151..d7aecab 100644
--- a/cputlb.c
+++ b/cputlb.c
@@ -125,8 +125,8 @@ void tlb_flush_page(CPUState *cpu, target_ulong addr)
    can be detected */
 void tlb_protect_code(ram_addr_t ram_addr)
 {
-    cpu_physical_memory_reset_dirty(ram_addr, TARGET_PAGE_SIZE,
-                                    DIRTY_MEMORY_CODE);
+    cpu_physical_memory_test_and_clear_dirty(ram_addr, TARGET_PAGE_SIZE,
+                                             DIRTY_MEMORY_CODE);
 }
 
 /* update the TLB so that writes in physical page 'phys_addr' are no longer
diff --git a/exec.c b/exec.c
index 83c58ff..42ed66e 100644
--- a/exec.c
+++ b/exec.c
@@ -857,16 +857,27 @@ static void tlb_reset_dirty_range_all(ram_addr_t start, ram_addr_t length)
 }
 
 /* Note: start and end must be within the same ram block.  */
-void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t length,
-                                     unsigned client)
+bool cpu_physical_memory_test_and_clear_dirty(ram_addr_t start,
+                                              ram_addr_t length,
+                                              unsigned client)
 {
-    if (length == 0)
-        return;
-    cpu_physical_memory_clear_dirty_range_type(start, length, client);
+    unsigned long end, page;
+    bool dirty;
+ 
+    if (length == 0) {
+        return false;
+    }
 
-    if (tcg_enabled()) {
+    end = TARGET_PAGE_ALIGN(start + length) >> TARGET_PAGE_BITS;
+    page = start >> TARGET_PAGE_BITS;
+    dirty = bitmap_test_and_clear_atomic(ram_list.dirty_memory[client],
+                                         page, end - page);
+
+    if (dirty && tcg_enabled()) {
         tlb_reset_dirty_range_all(start, length);
     }
+
+    return dirty;
 }
 
 /* Called from RCU critical section */
diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
index a68bde2..b7357ac 100644
--- a/include/exec/ram_addr.h
+++ b/include/exec/ram_addr.h
@@ -190,30 +190,19 @@ static inline void cpu_physical_memory_set_dirty_lebitmap(unsigned long *bitmap,
 }
 #endif /* not _WIN32 */
 
-static inline void cpu_physical_memory_clear_dirty_range_type(ram_addr_t start,
-                                                              ram_addr_t length,
-                                                              unsigned client)
-{
-    unsigned long end, page;
-
-    assert(client < DIRTY_MEMORY_NUM);
-    end = TARGET_PAGE_ALIGN(start + length) >> TARGET_PAGE_BITS;
-    page = start >> TARGET_PAGE_BITS;
-    bitmap_clear(ram_list.dirty_memory[client], page, end - page);
-}
+bool cpu_physical_memory_test_and_clear_dirty(ram_addr_t start,
+                                              ram_addr_t length,
+                                              unsigned client);
 
 static inline void cpu_physical_memory_clear_dirty_range(ram_addr_t start,
                                                          ram_addr_t length)
 {
-    cpu_physical_memory_clear_dirty_range_type(start, length, DIRTY_MEMORY_MIGRATION);
-    cpu_physical_memory_clear_dirty_range_type(start, length, DIRTY_MEMORY_VGA);
-    cpu_physical_memory_clear_dirty_range_type(start, length, DIRTY_MEMORY_CODE);
+    cpu_physical_memory_test_and_clear_dirty(start, length, DIRTY_MEMORY_MIGRATION);
+    cpu_physical_memory_test_and_clear_dirty(start, length, DIRTY_MEMORY_VGA);
+    cpu_physical_memory_test_and_clear_dirty(start, length, DIRTY_MEMORY_CODE);
 }
 
 
-void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t length,
-                                     unsigned client);
-
 static inline
 uint64_t cpu_physical_memory_sync_dirty_bitmap(unsigned long *dest,
                                                ram_addr_t start,
@@ -241,12 +230,10 @@ uint64_t cpu_physical_memory_sync_dirty_bitmap(unsigned long *dest,
         }
     } else {
         for (addr = 0; addr < length; addr += TARGET_PAGE_SIZE) {
-            if (cpu_physical_memory_get_dirty(start + addr,
-                                              TARGET_PAGE_SIZE,
-                                              DIRTY_MEMORY_MIGRATION)) {
-                cpu_physical_memory_reset_dirty(start + addr,
-                                                TARGET_PAGE_SIZE,
-                                                DIRTY_MEMORY_MIGRATION);
+            if (cpu_physical_memory_test_and_clear_dirty(
+                        start + addr,
+                        TARGET_PAGE_SIZE,
+                        DIRTY_MEMORY_MIGRATION)) {
                 long k = (start + addr) >> TARGET_PAGE_BITS;
                 if (!test_and_set_bit(k, dest)) {
                     num_dirty++;
diff --git a/memory.c b/memory.c
index 6061b27..3eea46f 100644
--- a/memory.c
+++ b/memory.c
@@ -1387,13 +1387,9 @@ void memory_region_set_dirty(MemoryRegion *mr, hwaddr addr,
 bool memory_region_test_and_clear_dirty(MemoryRegion *mr, hwaddr addr,
                                         hwaddr size, unsigned client)
 {
-    bool ret;
     assert(mr->terminates);
-    ret = cpu_physical_memory_get_dirty(mr->ram_addr + addr, size, client);
-    if (ret) {
-        cpu_physical_memory_reset_dirty(mr->ram_addr + addr, size, client);
-    }
-    return ret;
+    return cpu_physical_memory_test_and_clear_dirty(mr->ram_addr + addr,
+                                                    size, client);
 }
 
 
@@ -1437,7 +1433,8 @@ void memory_region_reset_dirty(MemoryRegion *mr, hwaddr addr,
                                hwaddr size, unsigned client)
 {
     assert(mr->terminates);
-    cpu_physical_memory_reset_dirty(mr->ram_addr + addr, size, client);
+    cpu_physical_memory_test_and_clear_dirty(mr->ram_addr + addr, size,
+                                             client);
 }
 
 int memory_region_get_fd(MemoryRegion *mr)
-- 
2.3.3

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [Qemu-devel] [PATCH 21/22] memory: make cpu_physical_memory_sync_dirty_bitmap() fully atomic
  2015-03-26 17:38 [Qemu-devel] [PATCH 00/22] Dirty bitmap atomic access and optimizations Paolo Bonzini
                   ` (19 preceding siblings ...)
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 20/22] memory: replace cpu_physical_memory_reset_dirty() with test-and-clear Paolo Bonzini
@ 2015-03-26 17:38 ` Paolo Bonzini
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 22/22] migration: run bitmap sync outside iothread lock Paolo Bonzini
  2015-04-20 13:23 ` [Qemu-devel] [PATCH 00/22] Dirty bitmap atomic access and optimizations Stefan Hajnoczi
  22 siblings, 0 replies; 39+ messages in thread
From: Paolo Bonzini @ 2015-03-26 17:38 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stefan Hajnoczi

From: Stefan Hajnoczi <stefanha@redhat.com>

The fast path of cpu_physical_memory_sync_dirty_bitmap() directly
manipulates the dirty bitmap.  Use atomic_xchg() to make the
test-and-clear atomic.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Message-Id: <1417519399-3166-7-git-send-email-stefanha@redhat.com>
[Only do xchg on nonzero words. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 include/exec/ram_addr.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
index b7357ac..c4e5624 100644
--- a/include/exec/ram_addr.h
+++ b/include/exec/ram_addr.h
@@ -220,12 +220,12 @@ uint64_t cpu_physical_memory_sync_dirty_bitmap(unsigned long *dest,
 
         for (k = page; k < page + nr; k++) {
             if (src[k]) {
+                unsigned long bits = atomic_xchg(&src[k], 0);
                 unsigned long new_dirty;
                 new_dirty = ~dest[k];
-                dest[k] |= src[k];
-                new_dirty &= src[k];
+                dest[k] |= bits;
+                new_dirty &= bits;
                 num_dirty += ctpopl(new_dirty);
-                src[k] = 0;
             }
         }
     } else {
-- 
2.3.3

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [Qemu-devel] [PATCH 22/22] migration: run bitmap sync outside iothread lock
  2015-03-26 17:38 [Qemu-devel] [PATCH 00/22] Dirty bitmap atomic access and optimizations Paolo Bonzini
                   ` (20 preceding siblings ...)
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 21/22] memory: make cpu_physical_memory_sync_dirty_bitmap() fully atomic Paolo Bonzini
@ 2015-03-26 17:38 ` Paolo Bonzini
  2015-04-20 13:23 ` [Qemu-devel] [PATCH 00/22] Dirty bitmap atomic access and optimizations Stefan Hajnoczi
  22 siblings, 0 replies; 39+ messages in thread
From: Paolo Bonzini @ 2015-03-26 17:38 UTC (permalink / raw)
  To: qemu-devel

Synchronization of the dirty bitmap can now run concurrently
with modifications of it.

Note that the change in migration_bitmap_sync is not needed
and is only for improved clarity.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 arch_init.c           | 10 +++++-----
 include/exec/memory.h |  8 ++++++++
 2 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/arch_init.c b/arch_init.c
index 75bba49..3ac63c6 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -512,10 +512,10 @@ static void migration_bitmap_sync(void)
         start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
     }
 
+    rcu_read_lock();
     trace_migration_bitmap_sync_start();
     address_space_sync_dirty_bitmap(&address_space_memory);
 
-    rcu_read_lock();
     QLIST_FOREACH_RCU(block, &ram_list.blocks, next) {
         migration_bitmap_sync_range(block->mr->ram_addr, block->used_length);
     }
@@ -838,7 +838,9 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
         acct_clear();
     }
 
-    /* iothread lock needed for ram_list.dirty_memory[] */
+    /* iothread lock needed for ram_list.dirty_memory[],
+     * ramlist lock needed for memory_global_dirty_log_start().
+     */
     qemu_mutex_lock_iothread();
     qemu_mutex_lock_ramlist();
     rcu_read_lock();
@@ -856,10 +858,10 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
     migration_dirty_pages = ram_bytes_total() >> TARGET_PAGE_BITS;
 
     memory_global_dirty_log_start();
-    migration_bitmap_sync();
     qemu_mutex_unlock_ramlist();
     qemu_mutex_unlock_iothread();
 
+    migration_bitmap_sync();
     qemu_put_be64(f, ram_bytes_total() | RAM_SAVE_FLAG_MEM_SIZE);
 
     QLIST_FOREACH_RCU(block, &ram_list.blocks, next) {
@@ -980,11 +982,9 @@ static uint64_t ram_save_pending(QEMUFile *f, void *opaque, uint64_t max_size)
     remaining_size = ram_save_remaining() * TARGET_PAGE_SIZE;
 
     if (remaining_size < max_size) {
-        qemu_mutex_lock_iothread();
         rcu_read_lock();
         migration_bitmap_sync();
         rcu_read_unlock();
-        qemu_mutex_unlock_iothread();
         remaining_size = ram_save_remaining() * TARGET_PAGE_SIZE;
     }
     return remaining_size;
diff --git a/include/exec/memory.h b/include/exec/memory.h
index aa46a52..e79e2d5 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -177,6 +177,9 @@ struct MemoryRegion {
  *
  * Allows a component to adjust to changes in the guest-visible memory map.
  * Use with memory_listener_register() and memory_listener_unregister().
+ *
+ * All functions called while holding the iothread lock, EXCEPT FOR log_sync
+ * which may be called either with or without the iothread lock held.
  */
 struct MemoryListener {
     void (*begin)(MemoryListener *listener);
@@ -682,6 +685,9 @@ bool memory_region_test_and_clear_dirty(MemoryRegion *mr, hwaddr addr,
  * Flushes dirty information from accelerators such as kvm and vhost-net
  * and makes it available to users of the memory API.
  *
+ * Unlike other memory region function, memory_region_sync_dirty_bitmap
+ * may be called either with or without the iothread lock held.
+ *
  * @mr: the region being flushed.
  */
 void memory_region_sync_dirty_bitmap(MemoryRegion *mr);
@@ -994,6 +1000,8 @@ MemoryRegionSection memory_region_find(MemoryRegion *mr,
  * address_space_sync_dirty_bitmap: synchronize the dirty log for all memory
  *
  * Synchronizes the dirty page log for an entire address space.
+ * May be called either with or without the iothread lock held.
+ *
  * @as: the address space that contains the memory being synchronized
  */
 void address_space_sync_dirty_bitmap(AddressSpace *as);
-- 
2.3.3

^ permalink raw reply related	[flat|nested] 39+ messages in thread

* Re: [Qemu-devel] [PATCH 05/22] memory: return bitmap from memory_region_is_logging
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 05/22] memory: return bitmap from memory_region_is_logging Paolo Bonzini
@ 2015-03-27  5:44   ` Fam Zheng
  2015-03-27  6:01     ` Paolo Bonzini
  2015-03-28 18:54   ` Michael S. Tsirkin
  1 sibling, 1 reply; 39+ messages in thread
From: Fam Zheng @ 2015-03-27  5:44 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel, Michael S. Tsirkin

On Thu, 03/26 18:38, Paolo Bonzini wrote:
> For now it only returns (1 << DIRTY_MEMORY_VGA) or 0, but this
> will change soon so adjust the callers.
> 
> Listeners check for "any bit except migration", which is handled
> via the global start/stop listener callbacks.  This in practice
> means VGA because the code bitmap is TCG-specific; however, be
> explicit, as for example things would be different if vhost ever
> ran with TCG.
> 
> Instead, the VMware VGA is looking explicitly for DIRTY_MEMORY_VGA.
> 
> Cc: Michael S. Tsirkin <mst@redhat.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>         This is the ugliest patch in the series.  My long-term plan
>         is to get rid of the global start/stop hooks in the
>         MemoryListeners.
> 
>  hw/display/vmware_vga.c | 2 +-
>  hw/virtio/vhost.c       | 3 ++-
>  include/exec/memory.h   | 5 +++--
>  kvm-all.c               | 3 ++-
>  memory.c                | 2 +-
>  xen-hvm.c               | 3 ++-
>  6 files changed, 11 insertions(+), 7 deletions(-)
> 
> diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c
> index c17ddd1..93d7426 100644
> --- a/hw/display/vmware_vga.c
> +++ b/hw/display/vmware_vga.c
> @@ -1124,7 +1124,7 @@ static void vmsvga_update_display(void *opaque)
>       * Is it more efficient to look at vram VGA-dirty bits or wait
>       * for the driver to issue SVGA_CMD_UPDATE?
>       */
> -    if (memory_region_is_logging(&s->vga.vram)) {
> +    if (memory_region_is_logging(&s->vga.vram) & (1 << DIRTY_MEMORY_VGA)) {
>          vga_sync_dirty_bitmap(&s->vga);
>          dirty = memory_region_get_dirty(&s->vga.vram, 0,
>              surface_stride(surface) * surface_height(surface),
> diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
> index 5a12861..59321ee 100644
> --- a/hw/virtio/vhost.c
> +++ b/hw/virtio/vhost.c
> @@ -377,7 +377,8 @@ static void vhost_set_memory(MemoryListener *listener,
>                                           memory_listener);
>      hwaddr start_addr = section->offset_within_address_space;
>      ram_addr_t size = int128_get64(section->size);
> -    bool log_dirty = memory_region_is_logging(section->mr);
> +    bool log_dirty =
> +        memory_region_is_logging(section->mr) & ~(1 << DIRTY_MEMORY_MIGRATION);

Based on the commit log that said memory_region_is_logging() only returns 0 or
(1 << DIRTY_MEMORY_VGA), the new code keeps the truth table. But I don't
understand why is DIRTY_MEMORY_MIGRATION excluded here and below?

Fam

>      int s = offsetof(struct vhost_memory, regions) +
>          (dev->mem->nregions + 1) * sizeof dev->mem->regions[0];
>      void *ram;
> diff --git a/include/exec/memory.h b/include/exec/memory.h
> index 081f7d6..8d5feb2 100644
> --- a/include/exec/memory.h
> +++ b/include/exec/memory.h
> @@ -569,11 +569,12 @@ const char *memory_region_name(const MemoryRegion *mr);
>  /**
>   * memory_region_is_logging: return whether a memory region is logging writes
>   *
> - * Returns %true if the memory region is logging writes
> + * Returns a bitmap of clients for which the memory region is logging writes.
> + * Right now this will be either 0 or (1 << DIRTY_MEMORY_VGA).
>   *
>   * @mr: the memory region being queried
>   */
> -bool memory_region_is_logging(MemoryRegion *mr);
> +uint8_t memory_region_is_logging(MemoryRegion *mr);
>  
>  /**
>   * memory_region_is_rom: check whether a memory region is ROM
> diff --git a/kvm-all.c b/kvm-all.c
> index 335438a..6962653 100644
> --- a/kvm-all.c
> +++ b/kvm-all.c
> @@ -663,7 +663,8 @@ static void kvm_set_phys_mem(MemoryRegionSection *section, bool add)
>      KVMSlot *mem, old;
>      int err;
>      MemoryRegion *mr = section->mr;
> -    bool log_dirty = memory_region_is_logging(mr);
> +    bool log_dirty =
> +        memory_region_is_logging(mr) & ~(1 << DIRTY_MEMORY_MIGRATION);
>      bool writeable = !mr->readonly && !mr->rom_device;
>      bool readonly_flag = mr->readonly || memory_region_is_romd(mr);
>      hwaddr start_addr = section->offset_within_address_space;
> diff --git a/memory.c b/memory.c
> index e688f5e..45606bc 100644
> --- a/memory.c
> +++ b/memory.c
> @@ -1318,7 +1318,7 @@ bool memory_region_is_skip_dump(MemoryRegion *mr)
>      return mr->skip_dump;
>  }
>  
> -bool memory_region_is_logging(MemoryRegion *mr)
> +uint8_t memory_region_is_logging(MemoryRegion *mr)
>  {
>      return mr->dirty_log_mask;
>  }
> diff --git a/xen-hvm.c b/xen-hvm.c
> index 315864c..acd89c8 100644
> --- a/xen-hvm.c
> +++ b/xen-hvm.c
> @@ -488,7 +488,8 @@ static void xen_set_memory(struct MemoryListener *listener,
>      XenIOState *state = container_of(listener, XenIOState, memory_listener);
>      hwaddr start_addr = section->offset_within_address_space;
>      ram_addr_t size = int128_get64(section->size);
> -    bool log_dirty = memory_region_is_logging(section->mr);
> +    bool log_dirty =
> +        memory_region_is_logging(section->mr) & ~(1 << DIRTY_MEMORY_MIGRATION);
>      hvmmem_type_t mem_type;
>  
>      if (section->mr == &ram_memory) {
> -- 
> 2.3.3
> 
> 
> 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [Qemu-devel] [PATCH 05/22] memory: return bitmap from memory_region_is_logging
  2015-03-27  5:44   ` Fam Zheng
@ 2015-03-27  6:01     ` Paolo Bonzini
  0 siblings, 0 replies; 39+ messages in thread
From: Paolo Bonzini @ 2015-03-27  6:01 UTC (permalink / raw)
  To: Fam Zheng; +Cc: qemu-devel, Michael S. Tsirkin



On 27/03/2015 06:44, Fam Zheng wrote:
> Based on the commit log that said memory_region_is_logging() only returns 0 or
> (1 << DIRTY_MEMORY_VGA), the new code keeps the truth table. But I don't
> understand why is DIRTY_MEMORY_MIGRATION excluded here and below?

Because DIRTY_MEMORY_MIGRATION is handled via the
log_global_start/log_global_stop mechanism.  The functions I'm patching
here are called only through region_add and region_del, so they do not
care about DIRTY_MEMORY_MIGRATION.

The plan is to remove this special case:

>         This is the ugliest patch in the series.  My long-term plan
>         is to get rid of the global start/stop hooks in the
>         MemoryListeners.

but it is not trivial so it's better done in a different patch series.

Paolo

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [Qemu-devel] [PATCH 14/22] exec: only check relevant bitmaps for cleanliness
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 14/22] exec: only check relevant bitmaps for cleanliness Paolo Bonzini
@ 2015-03-27  6:10   ` Fam Zheng
  2015-03-27  9:19     ` Paolo Bonzini
  0 siblings, 1 reply; 39+ messages in thread
From: Fam Zheng @ 2015-03-27  6:10 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel

On Thu, 03/26 18:38, Paolo Bonzini wrote:
> Most of the time, not all bitmaps have to be marked as dirty;
> do not do anything if the interesting ones are already dirty.
> Previously, any clean bitmap would have cause all the bitmaps to be
> marked dirty.
> 
> In fact, unless running TCG most of the time bitmap operations
> are not done at all because memory_region_is_logging returns
> zero.  In this case, skip cpu_physical_memory_range_includes_clean
> as well.
> 
> With this patch, cpu_physical_memory_set_dirty_range is called
> unconditionally, so there need not be anymore a separate call to
> xen_modified_memory.
> 
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  exec.c                  | 18 +++++++++---------
>  include/exec/ram_addr.h | 19 +++++++++++++------
>  2 files changed, 22 insertions(+), 15 deletions(-)
> 
> diff --git a/exec.c b/exec.c
> index 94b7644..83c58ff 100644
> --- a/exec.c
> +++ b/exec.c
> @@ -2236,16 +2236,16 @@ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
>  static void invalidate_and_set_dirty(MemoryRegion *mr, hwaddr addr,
>                                       hwaddr length)
>  {
> -    if (cpu_physical_memory_range_includes_clean(addr, length)) {
> -        uint8_t dirty_log_mask = memory_region_is_logging(mr);
> -        if (dirty_log_mask & (1 << DIRTY_MEMORY_CODE)) {
> -            tb_invalidate_phys_range(addr, addr + length, 0);
> -            dirty_log_mask &= ~(1 << DIRTY_MEMORY_CODE);
> -        }
> -        cpu_physical_memory_set_dirty_range(addr, length, dirty_log_mask);
> -    } else {
> -        xen_modified_memory(addr, length);
> +    uint8_t dirty_log_mask = memory_region_is_logging(mr);
> +    if (dirty_log_mask &&
> +        !cpu_physical_memory_range_includes_clean(addr, length, dirty_log_mask)) {
> +        dirty_log_mask = 0;
> +    }
> +    if (dirty_log_mask & (1 << DIRTY_MEMORY_CODE)) {
> +        tb_invalidate_phys_range(addr, addr + length, 0);
> +        dirty_log_mask &= ~(1 << DIRTY_MEMORY_CODE);
>      }
> +    cpu_physical_memory_set_dirty_range(addr, length, dirty_log_mask);
>  }
>  
>  static int memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr)
> diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
> index 6c3b74e..b408408 100644
> --- a/include/exec/ram_addr.h
> +++ b/include/exec/ram_addr.h
> @@ -90,13 +90,20 @@ static inline bool cpu_physical_memory_is_clean(ram_addr_t addr)
>  }
>  
>  static inline bool cpu_physical_memory_range_includes_clean(ram_addr_t start,
> -                                                            ram_addr_t length)
> +                                                            ram_addr_t length,
> +                                                            uint8_t mask)
>  {
> -    bool vga = cpu_physical_memory_get_clean(start, length, DIRTY_MEMORY_VGA);
> -    bool code = cpu_physical_memory_get_clean(start, length, DIRTY_MEMORY_CODE);
> -    bool migration =
> -        cpu_physical_memory_get_clean(start, length, DIRTY_MEMORY_MIGRATION);
> -    return vga || code || migration;
> +    bool clean = false;
> +    if (mask & (1 << DIRTY_MEMORY_VGA)) {
> +        clean = cpu_physical_memory_get_clean(start, length, DIRTY_MEMORY_VGA);
> +    }
> +    if (!clean && (mask & (1 << DIRTY_MEMORY_CODE))) {
> +        clean = cpu_physical_memory_get_clean(start, length, DIRTY_MEMORY_CODE);
> +    }
> +    if (!clean && (mask & (1 << DIRTY_MEMORY_MIGRATION))) {
> +        clean = cpu_physical_memory_get_clean(start, length, DIRTY_MEMORY_MIGRATION);
> +    }
> +    return clean;
>  }

Out of curiosity, is it valid that a mask bit is cleared but the corresponding
dirty bit is set?

>  
>  static inline void cpu_physical_memory_set_dirty_flag(ram_addr_t addr,
> -- 
> 2.3.3
> 
> 
> 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [Qemu-devel] [PATCH 17/22] bitmap: add atomic test and clear
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 17/22] bitmap: add atomic test and clear Paolo Bonzini
@ 2015-03-27  6:37   ` Fam Zheng
  2015-03-27  9:21     ` Paolo Bonzini
  0 siblings, 1 reply; 39+ messages in thread
From: Fam Zheng @ 2015-03-27  6:37 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel, Stefan Hajnoczi

On Thu, 03/26 18:38, Paolo Bonzini wrote:
> From: Stefan Hajnoczi <stefanha@redhat.com>
> 
> The new bitmap_test_and_clear_atomic() function clears a range and
> returns whether or not the bits were set.
> 
> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
> Message-Id: <1417519399-3166-3-git-send-email-stefanha@redhat.com>
> [Test before xchg; then a full barrier is needed at the end just like
>  in the previous patch.  The barrier can be avoided if we did at least
>  one xchg.  - Paolo]
> 
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  include/qemu/bitmap.h |  2 ++
>  util/bitmap.c         | 43 +++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 45 insertions(+)
> 
> diff --git a/include/qemu/bitmap.h b/include/qemu/bitmap.h
> index 3e0a4f3..86dd9cd 100644
> --- a/include/qemu/bitmap.h
> +++ b/include/qemu/bitmap.h
> @@ -41,6 +41,7 @@
>   * bitmap_set(dst, pos, nbits)			Set specified bit area
>   * bitmap_set_atomic(dst, pos, nbits)   Set specified bit area with atomic ops
>   * bitmap_clear(dst, pos, nbits)		Clear specified bit area
> + * bitmap_test_and_clear_atomic(dst, pos, nbits)    Test and clear area
>   * bitmap_find_next_zero_area(buf, len, pos, n, mask)	Find bit free area
>   */
>  
> @@ -229,6 +230,7 @@ static inline int bitmap_intersects(const unsigned long *src1,
>  void bitmap_set(unsigned long *map, long i, long len);
>  void bitmap_set_atomic(unsigned long *map, long i, long len);
>  void bitmap_clear(unsigned long *map, long start, long nr);
> +bool bitmap_test_and_clear_atomic(unsigned long *map, long start, long nr);
>  unsigned long bitmap_find_next_zero_area(unsigned long *map,
>                                           unsigned long size,
>                                           unsigned long start,
> diff --git a/util/bitmap.c b/util/bitmap.c
> index e4957da..570758a 100644
> --- a/util/bitmap.c
> +++ b/util/bitmap.c
> @@ -232,6 +232,49 @@ void bitmap_clear(unsigned long *map, long start, long nr)
>      }
>  }
>  
> +bool bitmap_test_and_clear_atomic(unsigned long *map, long start, long nr)
> +{
> +    unsigned long *p = map + BIT_WORD(start);
> +    const long size = start + nr;
> +    int bits_to_clear = BITS_PER_LONG - (start % BITS_PER_LONG);
> +    unsigned long mask_to_clear = BITMAP_FIRST_WORD_MASK(start);
> +    unsigned long dirty = 0;
> +    unsigned long old_bits;
> +
> +    /* First word */
> +    if (nr - bits_to_clear > 0) {
> +        old_bits = atomic_fetch_and(p, ~mask_to_clear);
> +        dirty |= old_bits & mask_to_clear;
> +        nr -= bits_to_clear;
> +        bits_to_clear = BITS_PER_LONG;
> +        mask_to_clear = ~0UL;
> +        p++;
> +    }
> +
> +    /* Full words */
> +    while (nr - bits_to_clear >= 0) {
> +        if (*p) {
> +            old_bits = atomic_xchg(p, 0);
> +            dirty |= old_bits;
> +        }
> +        nr -= bits_to_clear;
> +        p++;
> +    }
> +
> +    /* Last word */
> +    if (nr) {
> +        mask_to_clear &= BITMAP_LAST_WORD_MASK(size);
> +        old_bits = atomic_fetch_and(p, ~mask_to_clear);
> +        dirty |= old_bits & mask_to_clear;
> +    } else {
> +        if (!dirty) {
> +            smp_mb();

Is this for the "*p" in the while loop? If so, and if the while loop is not
executed (bits contained in the first word, and clean), isn't this barrier
superfluous then?

Fam

> +        }
> +    }
> +
> +    return dirty;
> +}
> +
>  #define ALIGN_MASK(x,mask)      (((x)+(mask))&~(mask))
>  
>  /**
> -- 
> 2.3.3
> 
> 
> 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [Qemu-devel] [PATCH 14/22] exec: only check relevant bitmaps for cleanliness
  2015-03-27  6:10   ` Fam Zheng
@ 2015-03-27  9:19     ` Paolo Bonzini
  0 siblings, 0 replies; 39+ messages in thread
From: Paolo Bonzini @ 2015-03-27  9:19 UTC (permalink / raw)
  To: Fam Zheng; +Cc: qemu-devel



On 27/03/2015 07:10, Fam Zheng wrote:
>>  static inline bool cpu_physical_memory_range_includes_clean(ram_addr_t start,
>> -                                                            ram_addr_t length)
>> +                                                            ram_addr_t length,
>> +                                                            uint8_t mask)
>>  {
>> -    bool vga = cpu_physical_memory_get_clean(start, length, DIRTY_MEMORY_VGA);
>> -    bool code = cpu_physical_memory_get_clean(start, length, DIRTY_MEMORY_CODE);
>> -    bool migration =
>> -        cpu_physical_memory_get_clean(start, length, DIRTY_MEMORY_MIGRATION);
>> -    return vga || code || migration;
>> +    bool clean = false;
>> +    if (mask & (1 << DIRTY_MEMORY_VGA)) {
>> +        clean = cpu_physical_memory_get_clean(start, length, DIRTY_MEMORY_VGA);
>> +    }
>> +    if (!clean && (mask & (1 << DIRTY_MEMORY_CODE))) {
>> +        clean = cpu_physical_memory_get_clean(start, length, DIRTY_MEMORY_CODE);
>> +    }
>> +    if (!clean && (mask & (1 << DIRTY_MEMORY_MIGRATION))) {
>> +        clean = cpu_physical_memory_get_clean(start, length, DIRTY_MEMORY_MIGRATION);
>> +    }
>> +    return clean;
>>  }
> 
> Out of curiosity, is it valid that a mask bit is cleared but the corresponding
> dirty bit is set?

Yes, for example if migration is cancelled you'll have some bits set in
the DIRTY_MEMORY_MIGRATION bitmap, but DIRTY_MEMORY_MIGRATION itself
will not be enabled.

Paolo

>>  
>>  static inline void cpu_physical_memory_set_dirty_flag(ram_addr_t addr,
>> -- 
>> 2.3.3
>>
>>
>>

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [Qemu-devel] [PATCH 17/22] bitmap: add atomic test and clear
  2015-03-27  6:37   ` Fam Zheng
@ 2015-03-27  9:21     ` Paolo Bonzini
  0 siblings, 0 replies; 39+ messages in thread
From: Paolo Bonzini @ 2015-03-27  9:21 UTC (permalink / raw)
  To: Fam Zheng; +Cc: qemu-devel, Stefan Hajnoczi



On 27/03/2015 07:37, Fam Zheng wrote:
> On Thu, 03/26 18:38, Paolo Bonzini wrote:
>> From: Stefan Hajnoczi <stefanha@redhat.com>
>>
>> The new bitmap_test_and_clear_atomic() function clears a range and
>> returns whether or not the bits were set.
>>
>> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
>> Message-Id: <1417519399-3166-3-git-send-email-stefanha@redhat.com>
>> [Test before xchg; then a full barrier is needed at the end just like
>>  in the previous patch.  The barrier can be avoided if we did at least
>>  one xchg.  - Paolo]
>>
>> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
>> ---
>>  include/qemu/bitmap.h |  2 ++
>>  util/bitmap.c         | 43 +++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 45 insertions(+)
>>
>> diff --git a/include/qemu/bitmap.h b/include/qemu/bitmap.h
>> index 3e0a4f3..86dd9cd 100644
>> --- a/include/qemu/bitmap.h
>> +++ b/include/qemu/bitmap.h
>> @@ -41,6 +41,7 @@
>>   * bitmap_set(dst, pos, nbits)			Set specified bit area
>>   * bitmap_set_atomic(dst, pos, nbits)   Set specified bit area with atomic ops
>>   * bitmap_clear(dst, pos, nbits)		Clear specified bit area
>> + * bitmap_test_and_clear_atomic(dst, pos, nbits)    Test and clear area
>>   * bitmap_find_next_zero_area(buf, len, pos, n, mask)	Find bit free area
>>   */
>>  
>> @@ -229,6 +230,7 @@ static inline int bitmap_intersects(const unsigned long *src1,
>>  void bitmap_set(unsigned long *map, long i, long len);
>>  void bitmap_set_atomic(unsigned long *map, long i, long len);
>>  void bitmap_clear(unsigned long *map, long start, long nr);
>> +bool bitmap_test_and_clear_atomic(unsigned long *map, long start, long nr);
>>  unsigned long bitmap_find_next_zero_area(unsigned long *map,
>>                                           unsigned long size,
>>                                           unsigned long start,
>> diff --git a/util/bitmap.c b/util/bitmap.c
>> index e4957da..570758a 100644
>> --- a/util/bitmap.c
>> +++ b/util/bitmap.c
>> @@ -232,6 +232,49 @@ void bitmap_clear(unsigned long *map, long start, long nr)
>>      }
>>  }
>>  
>> +bool bitmap_test_and_clear_atomic(unsigned long *map, long start, long nr)
>> +{
>> +    unsigned long *p = map + BIT_WORD(start);
>> +    const long size = start + nr;
>> +    int bits_to_clear = BITS_PER_LONG - (start % BITS_PER_LONG);
>> +    unsigned long mask_to_clear = BITMAP_FIRST_WORD_MASK(start);
>> +    unsigned long dirty = 0;
>> +    unsigned long old_bits;
>> +
>> +    /* First word */
>> +    if (nr - bits_to_clear > 0) {
>> +        old_bits = atomic_fetch_and(p, ~mask_to_clear);
>> +        dirty |= old_bits & mask_to_clear;
>> +        nr -= bits_to_clear;
>> +        bits_to_clear = BITS_PER_LONG;
>> +        mask_to_clear = ~0UL;
>> +        p++;
>> +    }
>> +
>> +    /* Full words */
>> +    while (nr - bits_to_clear >= 0) {
>> +        if (*p) {
>> +            old_bits = atomic_xchg(p, 0);
>> +            dirty |= old_bits;
>> +        }
>> +        nr -= bits_to_clear;
>> +        p++;
>> +    }
>> +
>> +    /* Last word */
>> +    if (nr) {
>> +        mask_to_clear &= BITMAP_LAST_WORD_MASK(size);
>> +        old_bits = atomic_fetch_and(p, ~mask_to_clear);
>> +        dirty |= old_bits & mask_to_clear;
>> +    } else {
>> +        if (!dirty) {
>> +            smp_mb();
> 
> Is this for the "*p" in the while loop?

Yes, this is why it's within "if (!dirty)".  If any bit was set, an
atomic_xchg was done and the memory barrier is not needed.

> If so, and if the while loop is not
> executed (bits contained in the first word, and clean), isn't this barrier
> superfluous then?

Yes, I can add an "if (*p)" in the first if too.

Paolo

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [Qemu-devel] [PATCH 05/22] memory: return bitmap from memory_region_is_logging
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 05/22] memory: return bitmap from memory_region_is_logging Paolo Bonzini
  2015-03-27  5:44   ` Fam Zheng
@ 2015-03-28 18:54   ` Michael S. Tsirkin
  2015-03-29  7:33     ` Paolo Bonzini
  1 sibling, 1 reply; 39+ messages in thread
From: Michael S. Tsirkin @ 2015-03-28 18:54 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel

On Thu, Mar 26, 2015 at 06:38:23PM +0100, Paolo Bonzini wrote:
> For now it only returns (1 << DIRTY_MEMORY_VGA) or 0, but this
> will change soon so adjust the callers.
> 
> Listeners check for "any bit except migration", which is handled
> via the global start/stop listener callbacks.  This in practice
> means VGA because the code bitmap is TCG-specific; however, be
> explicit, as for example things would be different if vhost ever
> ran with TCG.
> 
> Instead, the VMware VGA is looking explicitly for DIRTY_MEMORY_VGA.
> 
> Cc: Michael S. Tsirkin <mst@redhat.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>         This is the ugliest patch in the series.  My long-term plan
>         is to get rid of the global start/stop hooks in the
>         MemoryListeners.
> 
>  hw/display/vmware_vga.c | 2 +-
>  hw/virtio/vhost.c       | 3 ++-
>  include/exec/memory.h   | 5 +++--
>  kvm-all.c               | 3 ++-
>  memory.c                | 2 +-
>  xen-hvm.c               | 3 ++-
>  6 files changed, 11 insertions(+), 7 deletions(-)
> 
> diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c
> index c17ddd1..93d7426 100644
> --- a/hw/display/vmware_vga.c
> +++ b/hw/display/vmware_vga.c
> @@ -1124,7 +1124,7 @@ static void vmsvga_update_display(void *opaque)
>       * Is it more efficient to look at vram VGA-dirty bits or wait
>       * for the driver to issue SVGA_CMD_UPDATE?
>       */
> -    if (memory_region_is_logging(&s->vga.vram)) {
> +    if (memory_region_is_logging(&s->vga.vram) & (1 << DIRTY_MEMORY_VGA)) {
>          vga_sync_dirty_bitmap(&s->vga);
>          dirty = memory_region_get_dirty(&s->vga.vram, 0,
>              surface_stride(surface) * surface_height(surface),
> diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
> index 5a12861..59321ee 100644
> --- a/hw/virtio/vhost.c
> +++ b/hw/virtio/vhost.c
> @@ -377,7 +377,8 @@ static void vhost_set_memory(MemoryListener *listener,
>                                           memory_listener);
>      hwaddr start_addr = section->offset_within_address_space;
>      ram_addr_t size = int128_get64(section->size);
> -    bool log_dirty = memory_region_is_logging(section->mr);
> +    bool log_dirty =
> +        memory_region_is_logging(section->mr) & ~(1 << DIRTY_MEMORY_MIGRATION);
>      int s = offsetof(struct vhost_memory, regions) +
>          (dev->mem->nregions + 1) * sizeof dev->mem->regions[0];
>      void *ram;
> diff --git a/include/exec/memory.h b/include/exec/memory.h
> index 081f7d6..8d5feb2 100644
> --- a/include/exec/memory.h
> +++ b/include/exec/memory.h
> @@ -569,11 +569,12 @@ const char *memory_region_name(const MemoryRegion *mr);
>  /**
>   * memory_region_is_logging: return whether a memory region is logging writes
>   *
> - * Returns %true if the memory region is logging writes
> + * Returns a bitmap of clients for which the memory region is logging writes.
> + * Right now this will be either 0 or (1 << DIRTY_MEMORY_VGA).
>   *
>   * @mr: the memory region being queried
>   */
> -bool memory_region_is_logging(MemoryRegion *mr);
> +uint8_t memory_region_is_logging(MemoryRegion *mr);
>  
>  /**
>   * memory_region_is_rom: check whether a memory region is ROM
> diff --git a/kvm-all.c b/kvm-all.c
> index 335438a..6962653 100644
> --- a/kvm-all.c
> +++ b/kvm-all.c
> @@ -663,7 +663,8 @@ static void kvm_set_phys_mem(MemoryRegionSection *section, bool add)
>      KVMSlot *mem, old;
>      int err;
>      MemoryRegion *mr = section->mr;
> -    bool log_dirty = memory_region_is_logging(mr);
> +    bool log_dirty =
> +        memory_region_is_logging(mr) & ~(1 << DIRTY_MEMORY_MIGRATION);
>      bool writeable = !mr->readonly && !mr->rom_device;
>      bool readonly_flag = mr->readonly || memory_region_is_romd(mr);
>      hwaddr start_addr = section->offset_within_address_space;
> diff --git a/memory.c b/memory.c
> index e688f5e..45606bc 100644
> --- a/memory.c
> +++ b/memory.c
> @@ -1318,7 +1318,7 @@ bool memory_region_is_skip_dump(MemoryRegion *mr)
>      return mr->skip_dump;
>  }
>  
> -bool memory_region_is_logging(MemoryRegion *mr)
> +uint8_t memory_region_is_logging(MemoryRegion *mr)
>  {
>      return mr->dirty_log_mask;
>  }

This API is pretty easy to misuse, and return
value is completely undocumented. In fact, if I see
"is" I assume a boolean return type.

As you are touching all users anyway, how about
wrappers that answer specific questions:
memory_region_is_logging_dirty_memory_vga
memory_region_is_logging_dirty_memory_migration
memory_region_is_logging_dirty_memory_except_migration
?

As a bonus, compiler will catch you if you forget to
change some caller.

> diff --git a/xen-hvm.c b/xen-hvm.c
> index 315864c..acd89c8 100644
> --- a/xen-hvm.c
> +++ b/xen-hvm.c
> @@ -488,7 +488,8 @@ static void xen_set_memory(struct MemoryListener *listener,
>      XenIOState *state = container_of(listener, XenIOState, memory_listener);
>      hwaddr start_addr = section->offset_within_address_space;
>      ram_addr_t size = int128_get64(section->size);
> -    bool log_dirty = memory_region_is_logging(section->mr);
> +    bool log_dirty =
> +        memory_region_is_logging(section->mr) & ~(1 << DIRTY_MEMORY_MIGRATION);
>      hvmmem_type_t mem_type;
>  
>      if (section->mr == &ram_memory) {
> -- 
> 2.3.3
> 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [Qemu-devel] [PATCH 01/22] memory: add memory_region_ram_resize
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 01/22] memory: add memory_region_ram_resize Paolo Bonzini
@ 2015-03-28 18:58   ` Michael S. Tsirkin
  2015-03-29  7:30     ` Paolo Bonzini
  0 siblings, 1 reply; 39+ messages in thread
From: Michael S. Tsirkin @ 2015-03-28 18:58 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel

On Thu, Mar 26, 2015 at 06:38:19PM +0100, Paolo Bonzini wrote:
> This is a simple MemoryRegion wrapper for qemu_ram_resize.
> 
> Cc: Michael S. Tsirkin <mst@redhat.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  include/exec/memory.h | 12 ++++++++++++
>  memory.c              |  7 +++++++
>  2 files changed, 19 insertions(+)
> 
> diff --git a/include/exec/memory.h b/include/exec/memory.h
> index 06ffa1d..a2ea587 100644
> --- a/include/exec/memory.h
> +++ b/include/exec/memory.h
> @@ -605,6 +605,18 @@ int memory_region_get_fd(MemoryRegion *mr);
>   */
>  void *memory_region_get_ram_ptr(MemoryRegion *mr);
>  
> +/* memory_region_ram_resize: Resize a RAM region.
> + *
> + * Only legal before guest might have detected the memory size: e.g. on
> + * incoming migration, or right after reset.
> + *
> + * @mr: a memory region created with @memory_region_init_resizeable_ram.
> + * @newsize: the new size the region
> + * @errp: pointer to Error*, to store an error if it happens.
> + */
> +void memory_region_ram_resize(MemoryRegion *mr, ram_addr_t newsize,
> +                              Error **errp);
> +
>  /**
>   * memory_region_set_log: Turn dirty logging on or off for a region.
>   *
> diff --git a/memory.c b/memory.c
> index ee3f2a8..a11e9bf 100644
> --- a/memory.c
> +++ b/memory.c
> @@ -1452,6 +1452,13 @@ void *memory_region_get_ram_ptr(MemoryRegion *mr)
>      return qemu_get_ram_ptr(mr->ram_addr & TARGET_PAGE_MASK);
>  }
>  
> +void memory_region_ram_resize(MemoryRegion *mr, ram_addr_t newsize, Error **errp)
> +{
> +    assert(mr->terminates);

Why? Does "terminates" guarantee that ram_addr
is valid? In any case, I think this needs a comment.

> +
> +    qemu_ram_resize(mr->ram_addr, newsize, errp);
> +}
> +
>  static void memory_region_update_coalesced_range_as(MemoryRegion *mr, AddressSpace *as)
>  {
>      FlatView *view;
> -- 
> 2.3.3
> 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [Qemu-devel] [PATCH 02/22] acpi-build: remove dependency from ram_addr.h
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 02/22] acpi-build: remove dependency from ram_addr.h Paolo Bonzini
@ 2015-03-28 18:58   ` Michael S. Tsirkin
  0 siblings, 0 replies; 39+ messages in thread
From: Michael S. Tsirkin @ 2015-03-28 18:58 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel

On Thu, Mar 26, 2015 at 06:38:20PM +0100, Paolo Bonzini wrote:
> ram_addr_t is an internal interface, everyone should go through
> MemoryRegion.  Clean it up by making rom_add_blob return a
> MemoryRegion* and using the new qemu_ram_resize infrastructure.
> 
> Cc: Michael S. Tsirkin <mst@redhat.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

Reviewed-by: Michael S. Tsirkin <mst@redhat.com>

> ---
>  hw/core/loader.c     |  8 ++++----
>  hw/i386/acpi-build.c | 36 ++++++++++++++++++------------------
>  include/hw/loader.h  |  8 +++++---
>  3 files changed, 27 insertions(+), 25 deletions(-)
> 
> diff --git a/hw/core/loader.c b/hw/core/loader.c
> index d4c441f..7ee675c 100644
> --- a/hw/core/loader.c
> +++ b/hw/core/loader.c
> @@ -835,12 +835,12 @@ err:
>      return -1;
>  }
>  
> -ram_addr_t rom_add_blob(const char *name, const void *blob, size_t len,
> +MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len,
>                     size_t max_len, hwaddr addr, const char *fw_file_name,
>                     FWCfgReadCallback fw_callback, void *callback_opaque)
>  {
>      Rom *rom;
> -    ram_addr_t ret = RAM_ADDR_MAX;
> +    MemoryRegion *mr = NULL;
>  
>      rom           = g_malloc0(sizeof(*rom));
>      rom->name     = g_strdup(name);
> @@ -858,7 +858,7 @@ ram_addr_t rom_add_blob(const char *name, const void *blob, size_t len,
>  
>          if (rom_file_has_mr) {
>              data = rom_set_mr(rom, OBJECT(fw_cfg), devpath);
> -            ret = memory_region_get_ram_addr(rom->mr);
> +            mr = rom->mr;
>          } else {
>              data = rom->data;
>          }
> @@ -867,7 +867,7 @@ ram_addr_t rom_add_blob(const char *name, const void *blob, size_t len,
>                                   fw_callback, callback_opaque,
>                                   data, rom->datasize);
>      }
> -    return ret;
> +    return mr;
>  }
>  
>  /* This function is specific for elf program because we don't need to allocate
> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
> index d0a5c85..ec4d1e8 100644
> --- a/hw/i386/acpi-build.c
> +++ b/hw/i386/acpi-build.c
> @@ -58,7 +58,6 @@
>  
>  #include "qapi/qmp/qint.h"
>  #include "qom/qom-qobject.h"
> -#include "exec/ram_addr.h"
>  
>  /* These are used to size the ACPI tables for -M pc-i440fx-1.7 and
>   * -M pc-i440fx-2.0.  Even if the actual amount of AML generated grows
> @@ -1323,13 +1322,13 @@ static inline void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool mfre)
>  typedef
>  struct AcpiBuildState {
>      /* Copy of table in RAM (for patching). */
> -    ram_addr_t table_ram;
> +    MemoryRegion *table_mr;
>      /* Is table patched? */
>      uint8_t patched;
>      PcGuestInfo *guest_info;
>      void *rsdp;
> -    ram_addr_t rsdp_ram;
> -    ram_addr_t linker_ram;
> +    MemoryRegion *rsdp_mr;
> +    MemoryRegion *linker_mr;
>  } AcpiBuildState;
>  
>  static bool acpi_get_mcfg(AcpiMcfgInfo *mcfg)
> @@ -1513,15 +1512,15 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables)
>      g_array_free(table_offsets, true);
>  }
>  
> -static void acpi_ram_update(ram_addr_t ram, GArray *data)
> +static void acpi_ram_update(MemoryRegion *mr, GArray *data)
>  {
>      uint32_t size = acpi_data_len(data);
>  
>      /* Make sure RAM size is correct - in case it got changed e.g. by migration */
> -    qemu_ram_resize(ram, size, &error_abort);
> +    memory_region_ram_resize(mr, size, &error_abort);
>  
> -    memcpy(qemu_get_ram_ptr(ram), data->data, size);
> -    cpu_physical_memory_set_dirty_range_nocode(ram, size);
> +    memcpy(memory_region_get_ram_ptr(mr), data->data, size);
> +    memory_region_set_dirty(mr, 0, size);
>  }
>  
>  static void acpi_build_update(void *build_opaque, uint32_t offset)
> @@ -1539,15 +1538,15 @@ static void acpi_build_update(void *build_opaque, uint32_t offset)
>  
>      acpi_build(build_state->guest_info, &tables);
>  
> -    acpi_ram_update(build_state->table_ram, tables.table_data);
> +    acpi_ram_update(build_state->table_mr, tables.table_data);
>  
>      if (build_state->rsdp) {
>          memcpy(build_state->rsdp, tables.rsdp->data, acpi_data_len(tables.rsdp));
>      } else {
> -        acpi_ram_update(build_state->rsdp_ram, tables.rsdp);
> +        acpi_ram_update(build_state->rsdp_mr, tables.rsdp);
>      }
>  
> -    acpi_ram_update(build_state->linker_ram, tables.linker);
> +    acpi_ram_update(build_state->linker_mr, tables.linker);
>      acpi_build_tables_cleanup(&tables, true);
>  }
>  
> @@ -1557,8 +1556,9 @@ static void acpi_build_reset(void *build_opaque)
>      build_state->patched = 0;
>  }
>  
> -static ram_addr_t acpi_add_rom_blob(AcpiBuildState *build_state, GArray *blob,
> -                               const char *name, uint64_t max_size)
> +static MemoryRegion *acpi_add_rom_blob(AcpiBuildState *build_state,
> +                                       GArray *blob, const char *name,
> +                                       uint64_t max_size)
>  {
>      return rom_add_blob(name, blob->data, acpi_data_len(blob), max_size, -1,
>                          name, acpi_build_update, build_state);
> @@ -1604,12 +1604,12 @@ void acpi_setup(PcGuestInfo *guest_info)
>      acpi_build(build_state->guest_info, &tables);
>  
>      /* Now expose it all to Guest */
> -    build_state->table_ram = acpi_add_rom_blob(build_state, tables.table_data,
> +    build_state->table_mr = acpi_add_rom_blob(build_state, tables.table_data,
>                                                 ACPI_BUILD_TABLE_FILE,
>                                                 ACPI_BUILD_TABLE_MAX_SIZE);
> -    assert(build_state->table_ram != RAM_ADDR_MAX);
> +    assert(build_state->table_mr != NULL);
>  
> -    build_state->linker_ram =
> +    build_state->linker_mr =
>          acpi_add_rom_blob(build_state, tables.linker, "etc/table-loader", 0);
>  
>      fw_cfg_add_file(guest_info->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
> @@ -1627,10 +1627,10 @@ void acpi_setup(PcGuestInfo *guest_info)
>          fw_cfg_add_file_callback(guest_info->fw_cfg, ACPI_BUILD_RSDP_FILE,
>                                   acpi_build_update, build_state,
>                                   build_state->rsdp, rsdp_size);
> -        build_state->rsdp_ram = (ram_addr_t)-1;
> +        build_state->rsdp_mr = NULL;
>      } else {
>          build_state->rsdp = NULL;
> -        build_state->rsdp_ram = acpi_add_rom_blob(build_state, tables.rsdp,
> +        build_state->rsdp_mr = acpi_add_rom_blob(build_state, tables.rsdp,
>                                                    ACPI_BUILD_RSDP_FILE, 0);
>      }
>  
> diff --git a/include/hw/loader.h b/include/hw/loader.h
> index 4f0681b..485ff8f 100644
> --- a/include/hw/loader.h
> +++ b/include/hw/loader.h
> @@ -68,9 +68,11 @@ extern bool rom_file_has_mr;
>  int rom_add_file(const char *file, const char *fw_dir,
>                   hwaddr addr, int32_t bootindex,
>                   bool option_rom);
> -ram_addr_t rom_add_blob(const char *name, const void *blob, size_t len,
> -                   size_t max_len, hwaddr addr, const char *fw_file_name,
> -                   FWCfgReadCallback fw_callback, void *callback_opaque);
> +MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len,
> +                           size_t max_len, hwaddr addr,
> +                           const char *fw_file_name,
> +                           FWCfgReadCallback fw_callback,
> +                           void *callback_opaque);
>  int rom_add_elf_program(const char *name, void *data, size_t datasize,
>                          size_t romsize, hwaddr addr);
>  int rom_load_all(void);
> -- 
> 2.3.3
> 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [Qemu-devel] [PATCH 10/22] ram_addr: tweaks to xen_modified_memory
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 10/22] ram_addr: tweaks to xen_modified_memory Paolo Bonzini
@ 2015-03-28 19:04   ` Stefano Stabellini
  0 siblings, 0 replies; 39+ messages in thread
From: Stefano Stabellini @ 2015-03-28 19:04 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel

On Thu, 26 Mar 2015, Paolo Bonzini wrote:
> Invoke xen_modified_memory from cpu_physical_memory_set_dirty_range_nocode;
> it is akin to DIRTY_MEMORY_MIGRATION, so set it together with that bitmap.
> The remaining call from invalidate_and_set_dirty's "else" branch will go
> away soon.
> 
> Second, fix the second argument to the function in the
> cpu_physical_memory_set_dirty_lebitmap call site.  That function is only used
> by KVM, but it is better to be clean anyway.
> 
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>


>  exec.c                  | 3 ++-
>  include/exec/ram_addr.h | 3 ++-
>  2 files changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/exec.c b/exec.c
> index 8eb73fd..ffa57dd 100644
> --- a/exec.c
> +++ b/exec.c
> @@ -2261,8 +2261,9 @@ static void invalidate_and_set_dirty(hwaddr addr,
>      if (cpu_physical_memory_range_includes_clean(addr, length)) {
>          tb_invalidate_phys_range(addr, addr + length, 0);
>          cpu_physical_memory_set_dirty_range_nocode(addr, length);
> +    } else {
> +        xen_modified_memory(addr, length);
>      }
> -    xen_modified_memory(addr, length);
>  }
>  
>  static int memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr)
> diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
> index ff558a4..7f6e928 100644
> --- a/include/exec/ram_addr.h
> +++ b/include/exec/ram_addr.h
> @@ -112,6 +112,7 @@ static inline void cpu_physical_memory_set_dirty_range_nocode(ram_addr_t start,
>      page = start >> TARGET_PAGE_BITS;
>      bitmap_set(ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION], page, end - page);
>      bitmap_set(ram_list.dirty_memory[DIRTY_MEMORY_VGA], page, end - page);
> +    xen_modified_memory(start, length);
>  }
>  
>  static inline void cpu_physical_memory_set_dirty_range(ram_addr_t start,
> @@ -155,7 +156,7 @@ static inline void cpu_physical_memory_set_dirty_lebitmap(unsigned long *bitmap,
>                  ram_list.dirty_memory[DIRTY_MEMORY_CODE][page + k] |= temp;
>              }
>          }
> -        xen_modified_memory(start, pages);
> +        xen_modified_memory(start, pages << TARGET_PAGE_BITS);
>      } else {
>          /*
>           * bitmap-traveling is faster than memory-traveling (for addr...)
> -- 
> 2.3.3
> 
> 
> 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [Qemu-devel] [PATCH 01/22] memory: add memory_region_ram_resize
  2015-03-28 18:58   ` Michael S. Tsirkin
@ 2015-03-29  7:30     ` Paolo Bonzini
  0 siblings, 0 replies; 39+ messages in thread
From: Paolo Bonzini @ 2015-03-29  7:30 UTC (permalink / raw)
  To: Michael S. Tsirkin; +Cc: qemu-devel



On 28/03/2015 19:58, Michael S. Tsirkin wrote:
>> > +void memory_region_ram_resize(MemoryRegion *mr, ram_addr_t newsize, Error **errp)
>> > +{
>> > +    assert(mr->terminates);
> Why? Does "terminates" guarantee that ram_addr
> is valid? In any case, I think this needs a comment.

More or less, but not really; I was just cutting/pasting it from other
functions that use ram_addr.  I will clean it up.

Paolo

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [Qemu-devel] [PATCH 05/22] memory: return bitmap from memory_region_is_logging
  2015-03-28 18:54   ` Michael S. Tsirkin
@ 2015-03-29  7:33     ` Paolo Bonzini
  0 siblings, 0 replies; 39+ messages in thread
From: Paolo Bonzini @ 2015-03-29  7:33 UTC (permalink / raw)
  To: Michael S. Tsirkin; +Cc: qemu-devel



On 28/03/2015 19:54, Michael S. Tsirkin wrote:
> This API is pretty easy to misuse, and return
> value is completely undocumented. In fact, if I see
> "is" I assume a boolean return type.
> 
> As you are touching all users anyway, how about
> wrappers that answer specific questions:
> memory_region_is_logging_dirty_memory_vga
> memory_region_is_logging_dirty_memory_migration
> memory_region_is_logging_dirty_memory_except_migration
> ?

The full return value is used later in the series.

I'll add a "client" argument to memory_region_is_logging (so that the
compiler will catch anything I forger) and add
memory_region_get_dirty_log_mask for the other users.

Regarding memory_region_is_logging_dirty_memory_except_migration, it
will go away once migration stops being special cased via
log_global_start/log_global_stop.

Paolo

> As a bonus, compiler will catch you if you forget to
> change some caller.
> 
>> diff --git a/xen-hvm.c b/xen-hvm.c
>> index 315864c..acd89c8 100644
>> --- a/xen-hvm.c
>> +++ b/xen-hvm.c
>> @@ -488,7 +488,8 @@ static void xen_set_memory(struct MemoryListener *listener,
>>      XenIOState *state = container_of(listener, XenIOState, memory_listener);
>>      hwaddr start_addr = section->offset_within_address_space;
>>      ram_addr_t size = int128_get64(section->size);
>> -    bool log_dirty = memory_region_is_logging(section->mr);
>> +    bool log_dirty =
>> +        memory_region_is_logging(section->mr) & ~(1 << DIRTY_MEMORY_MIGRATION);
>>      hvmmem_type_t mem_type;
>>  
>>      if (section->mr == &ram_memory) {
>> -- 
>> 2.3.3
>>
> 
> 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [Qemu-devel] [PATCH 04/22] display: enable DIRTY_MEMORY_VGA tracking explicitly
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 04/22] display: enable DIRTY_MEMORY_VGA tracking explicitly Paolo Bonzini
@ 2015-04-20 13:11   ` Stefan Hajnoczi
  2015-04-20 13:54     ` Paolo Bonzini
  0 siblings, 1 reply; 39+ messages in thread
From: Stefan Hajnoczi @ 2015-04-20 13:11 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 706 bytes --]

On Thu, Mar 26, 2015 at 06:38:22PM +0100, Paolo Bonzini wrote:
> diff --git a/hw/display/g364fb.c b/hw/display/g364fb.c
> index 46f7b41..be62dd6 100644
> --- a/hw/display/g364fb.c
> +++ b/hw/display/g364fb.c
> @@ -489,7 +489,7 @@ static void g364fb_init(DeviceState *dev, G364State *s)
>      memory_region_init_ram_ptr(&s->mem_vram, NULL, "vram",
>                                 s->vram_size, s->vram);
>      vmstate_register_ram(&s->mem_vram, dev);
> -    memory_region_set_coalescing(&s->mem_vram);
> +    memory_region_set_log(&s->mem_vram, true, DIRTY_MEMORY_VGA);

This change isn't 100% clear to me.  I guess that coalescing
(performance optimization) doesn't make sense when logging is enabled?

[-- Attachment #2: Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [Qemu-devel] [PATCH 00/22] Dirty bitmap atomic access and optimizations
  2015-03-26 17:38 [Qemu-devel] [PATCH 00/22] Dirty bitmap atomic access and optimizations Paolo Bonzini
                   ` (21 preceding siblings ...)
  2015-03-26 17:38 ` [Qemu-devel] [PATCH 22/22] migration: run bitmap sync outside iothread lock Paolo Bonzini
@ 2015-04-20 13:23 ` Stefan Hajnoczi
  22 siblings, 0 replies; 39+ messages in thread
From: Stefan Hajnoczi @ 2015-04-20 13:23 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 4115 bytes --]

On Thu, Mar 26, 2015 at 06:38:18PM +0100, Paolo Bonzini wrote:
> QEMU is currently accessing the dirty bitmaps very liberally,
> which is understandable since the accesses are cheap.  This is
> however not good for squeezing maximum performance out of dataplane,
> and is also not good if the accesses become more expensive---as is
> the case when they use atomic primitives.
> 
> Patches 1-2 make acpi-build.h only use public memory APIs.
> 
> Patches 3-7 optimize access to the VGA dirty bitmap, by restricting
> it to video RAM only.
> 
> Patches 8-15 optimize access to the code and migration bitmaps,
> by tracking them respectively if TCG is enabled and if migration
> is in progress.  Note that the first iteration of migration already
> does not look at the migration bitmap (commit 70c8652, migration:
> do not search dirty pages in bulk stage, 2013-03-26).
> 
> Patches 16-21 are Stefan's patches to convert bitmap access to use
> atomic primitives.
> 
> While the main purpose of these patches is a working dirty bitmap
> for dataplane (and possibly multithreaded TCG), there's something
> that they are immediately useful for: patch 22 makes the migration
> thread synchronize the bitmap outside the big QEMU lock, thus
> removing the last source of jitter during the RAM copy phase of
> migration.
> 
> Please review and test! (it's available as branch "atomic-dirty"
> on my github repository)  In particular, I suspect that the
> postcopy patches might be good at finding bugs.
> 
> Paolo
> 
> Paolo Bonzini (16):
>   memory: add memory_region_ram_resize
>   acpi-build: remove dependency from ram_addr.h
>   memory: the only dirty memory flag for users is DIRTY_MEMORY_VGA
>   display: enable DIRTY_MEMORY_VGA tracking explicitly
>   memory: return bitmap from memory_region_is_logging
>   framebuffer: check memory_region_is_logging
>   ui/console: check memory_region_is_logging
>   memory: track DIRTY_MEMORY_CODE in mr->dirty_log_mask
>   memory: return DIRTY_MEMORY_MIGRATION from memory_region_is_logging
>   ram_addr: tweaks to xen_modified_memory
>   exec: simplify notdirty_mem_write
>   exec: use memory_region_is_logging to optimize dirty tracking
>   exec: pass client mask to cpu_physical_memory_set_dirty_range
>   exec: only check relevant bitmaps for cleanliness
>   memory: do not touch code dirty bitmap unless TCG is enabled
>   migration: run bitmap sync outside iothread lock
> 
> Stefan Hajnoczi (6):
>   bitmap: add atomic set functions
>   bitmap: add atomic test and clear
>   memory: use atomic ops for setting dirty memory bits
>   migration: move dirty bitmap sync to ram_addr.h
>   memory: replace cpu_physical_memory_reset_dirty() with test-and-clear
>   memory: make cpu_physical_memory_sync_dirty_bitmap() fully atomic
> 
>  arch_init.c                  |  56 +++----------------
>  cputlb.c                     |   4 +-
>  exec.c                       | 103 ++++++++++++++++------------------
>  hw/core/loader.c             |   8 +--
>  hw/display/cg3.c             |   1 +
>  hw/display/exynos4210_fimd.c |   7 ++-
>  hw/display/framebuffer.c     |  23 ++++++--
>  hw/display/g364fb.c          |   2 +-
>  hw/display/sm501.c           |   1 +
>  hw/display/tcx.c             |   1 +
>  hw/display/vmware_vga.c      |   2 +-
>  hw/i386/acpi-build.c         |  36 ++++++------
>  hw/virtio/vhost.c            |   3 +-
>  include/exec/memory.h        |  27 +++++++--
>  include/exec/ram_addr.h      | 128 ++++++++++++++++++++++++++++---------------
>  include/hw/loader.h          |   8 ++-
>  include/qemu/bitmap.h        |   4 ++
>  include/qemu/bitops.h        |  14 +++++
>  kvm-all.c                    |   3 +-
>  memory.c                     |  34 ++++++++----
>  ui/console.c                 |  14 +++--
>  util/bitmap.c                |  78 ++++++++++++++++++++++++++
>  xen-hvm.c                    |   3 +-
>  23 files changed, 356 insertions(+), 204 deletions(-)

Modulo the comments that have already been posted:

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>

[-- Attachment #2: Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [Qemu-devel] [PATCH 04/22] display: enable DIRTY_MEMORY_VGA tracking explicitly
  2015-04-20 13:11   ` Stefan Hajnoczi
@ 2015-04-20 13:54     ` Paolo Bonzini
  2015-04-22  9:12       ` Stefan Hajnoczi
  0 siblings, 1 reply; 39+ messages in thread
From: Paolo Bonzini @ 2015-04-20 13:54 UTC (permalink / raw)
  To: Stefan Hajnoczi; +Cc: qemu-devel



On 20/04/2015 15:11, Stefan Hajnoczi wrote:
>> -    memory_region_set_coalescing(&s->mem_vram); +
>> memory_region_set_log(&s->mem_vram, true, DIRTY_MEMORY_VGA);
> 
> This change isn't 100% clear to me.  I guess that coalescing 
> (performance optimization) doesn't make sense when logging is
> enabled?

No, it's just that coalescing is for MMIO, not RAM.  Setting
coalescing was a no-op.  I'll make this a separate patch.

Paolo

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [Qemu-devel] [PATCH 04/22] display: enable DIRTY_MEMORY_VGA tracking explicitly
  2015-04-20 13:54     ` Paolo Bonzini
@ 2015-04-22  9:12       ` Stefan Hajnoczi
  0 siblings, 0 replies; 39+ messages in thread
From: Stefan Hajnoczi @ 2015-04-22  9:12 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 537 bytes --]

On Mon, Apr 20, 2015 at 03:54:52PM +0200, Paolo Bonzini wrote:
> 
> 
> On 20/04/2015 15:11, Stefan Hajnoczi wrote:
> >> -    memory_region_set_coalescing(&s->mem_vram); +
> >> memory_region_set_log(&s->mem_vram, true, DIRTY_MEMORY_VGA);
> > 
> > This change isn't 100% clear to me.  I guess that coalescing 
> > (performance optimization) doesn't make sense when logging is
> > enabled?
> 
> No, it's just that coalescing is for MMIO, not RAM.  Setting
> coalescing was a no-op.  I'll make this a separate patch.

Thanks!

[-- Attachment #2: Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 39+ messages in thread

end of thread, other threads:[~2015-04-22  9:12 UTC | newest]

Thread overview: 39+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-03-26 17:38 [Qemu-devel] [PATCH 00/22] Dirty bitmap atomic access and optimizations Paolo Bonzini
2015-03-26 17:38 ` [Qemu-devel] [PATCH 01/22] memory: add memory_region_ram_resize Paolo Bonzini
2015-03-28 18:58   ` Michael S. Tsirkin
2015-03-29  7:30     ` Paolo Bonzini
2015-03-26 17:38 ` [Qemu-devel] [PATCH 02/22] acpi-build: remove dependency from ram_addr.h Paolo Bonzini
2015-03-28 18:58   ` Michael S. Tsirkin
2015-03-26 17:38 ` [Qemu-devel] [PATCH 03/22] memory: the only dirty memory flag for users is DIRTY_MEMORY_VGA Paolo Bonzini
2015-03-26 17:38 ` [Qemu-devel] [PATCH 04/22] display: enable DIRTY_MEMORY_VGA tracking explicitly Paolo Bonzini
2015-04-20 13:11   ` Stefan Hajnoczi
2015-04-20 13:54     ` Paolo Bonzini
2015-04-22  9:12       ` Stefan Hajnoczi
2015-03-26 17:38 ` [Qemu-devel] [PATCH 05/22] memory: return bitmap from memory_region_is_logging Paolo Bonzini
2015-03-27  5:44   ` Fam Zheng
2015-03-27  6:01     ` Paolo Bonzini
2015-03-28 18:54   ` Michael S. Tsirkin
2015-03-29  7:33     ` Paolo Bonzini
2015-03-26 17:38 ` [Qemu-devel] [PATCH 06/22] framebuffer: check memory_region_is_logging Paolo Bonzini
2015-03-26 17:38 ` [Qemu-devel] [PATCH 07/22] ui/console: " Paolo Bonzini
2015-03-26 17:38 ` [Qemu-devel] [PATCH 08/22] memory: track DIRTY_MEMORY_CODE in mr->dirty_log_mask Paolo Bonzini
2015-03-26 17:38 ` [Qemu-devel] [PATCH 09/22] memory: return DIRTY_MEMORY_MIGRATION from memory_region_is_logging Paolo Bonzini
2015-03-26 17:38 ` [Qemu-devel] [PATCH 10/22] ram_addr: tweaks to xen_modified_memory Paolo Bonzini
2015-03-28 19:04   ` Stefano Stabellini
2015-03-26 17:38 ` [Qemu-devel] [PATCH 11/22] exec: simplify notdirty_mem_write Paolo Bonzini
2015-03-26 17:38 ` [Qemu-devel] [PATCH 12/22] exec: use memory_region_is_logging to optimize dirty tracking Paolo Bonzini
2015-03-26 17:38 ` [Qemu-devel] [PATCH 13/22] exec: pass client mask to cpu_physical_memory_set_dirty_range Paolo Bonzini
2015-03-26 17:38 ` [Qemu-devel] [PATCH 14/22] exec: only check relevant bitmaps for cleanliness Paolo Bonzini
2015-03-27  6:10   ` Fam Zheng
2015-03-27  9:19     ` Paolo Bonzini
2015-03-26 17:38 ` [Qemu-devel] [PATCH 15/22] memory: do not touch code dirty bitmap unless TCG is enabled Paolo Bonzini
2015-03-26 17:38 ` [Qemu-devel] [PATCH 16/22] bitmap: add atomic set functions Paolo Bonzini
2015-03-26 17:38 ` [Qemu-devel] [PATCH 17/22] bitmap: add atomic test and clear Paolo Bonzini
2015-03-27  6:37   ` Fam Zheng
2015-03-27  9:21     ` Paolo Bonzini
2015-03-26 17:38 ` [Qemu-devel] [PATCH 18/22] memory: use atomic ops for setting dirty memory bits Paolo Bonzini
2015-03-26 17:38 ` [Qemu-devel] [PATCH 19/22] migration: move dirty bitmap sync to ram_addr.h Paolo Bonzini
2015-03-26 17:38 ` [Qemu-devel] [PATCH 20/22] memory: replace cpu_physical_memory_reset_dirty() with test-and-clear Paolo Bonzini
2015-03-26 17:38 ` [Qemu-devel] [PATCH 21/22] memory: make cpu_physical_memory_sync_dirty_bitmap() fully atomic Paolo Bonzini
2015-03-26 17:38 ` [Qemu-devel] [PATCH 22/22] migration: run bitmap sync outside iothread lock Paolo Bonzini
2015-04-20 13:23 ` [Qemu-devel] [PATCH 00/22] Dirty bitmap atomic access and optimizations Stefan Hajnoczi

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.