summaryrefslogtreecommitdiff
path: root/memory.c
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2016-09-23 11:08:54 +0200
committerPaolo Bonzini <pbonzini@redhat.com>2016-10-24 15:27:19 +0200
commit0a752eeea810a1c37f5de4edba355c35cfa42524 (patch)
tree6ba3e696159a2271c89aac298ecef4bda92eb913 /memory.c
parentadaad61c3c8efb5b4f21ad70c6e141215fdbb304 (diff)
downloadqemu-0a752eeea810a1c37f5de4edba355c35cfa42524.zip
memory: optimize memory_region_sync_dirty_bitmap
Avoid walking the FlatView of all address spaces. Most of the address spaces will have no log_sync callback on their listeners. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'memory.c')
-rw-r--r--memory.c18
1 files changed, 15 insertions, 3 deletions
diff --git a/memory.c b/memory.c
index c857722f86..edbc7012b6 100644
--- a/memory.c
+++ b/memory.c
@@ -1642,14 +1642,26 @@ bool memory_region_test_and_clear_dirty(MemoryRegion *mr, hwaddr addr,
void memory_region_sync_dirty_bitmap(MemoryRegion *mr)
{
+ MemoryListener *listener;
AddressSpace *as;
+ FlatView *view;
FlatRange *fr;
- QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
- FlatView *view = address_space_get_flatview(as);
+ /* If the same address space has multiple log_sync listeners, we
+ * visit that address space's FlatView multiple times. But because
+ * log_sync listeners are rare, it's still cheaper than walking each
+ * address space once.
+ */
+ QTAILQ_FOREACH(listener, &memory_listeners, link) {
+ if (!listener->log_sync) {
+ continue;
+ }
+ as = listener->address_space;
+ view = address_space_get_flatview(as);
FOR_EACH_FLAT_RANGE(fr, view) {
if (fr->mr == mr) {
- MEMORY_LISTENER_UPDATE_REGION(fr, as, Forward, log_sync);
+ MemoryRegionSection mrs = section_from_flat_range(fr, as);
+ listener->log_sync(listener, &mrs);
}
}
flatview_unref(view);