Each addition or deletion of an eventfd happens in its own MR transaction. This doesn't scale well with multiqueue devices that do 1:1 queue:vCPU mapping (e.g. virtio-scsi-pci or virtio-blk-pci) : these devices typically create at least one eventfd per queue and memory_region_transaction_commit(), which is called during commit, also loops on eventfds, resulting in a quadratic time complexity. This calls for batching : a device should be able to add or delete its eventfds in a single transaction.
Prepare ground for this by introducing extended versions of memory_region_add_eventfd() and memory_region_del_eventfd() that take an extra bool argument to control if a transaction should be started or not. No behavior change at this point. Signed-off-by: Greg Kurz <gr...@kaod.org> --- include/exec/memory.h | 48 ++++++++++++++++++++++++++++++++----------- softmmu/memory.c | 42 ++++++++++++++++++++++--------------- 2 files changed, 62 insertions(+), 28 deletions(-) diff --git a/include/exec/memory.h b/include/exec/memory.h index 5728a681b27d..98ed552e001c 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -1848,13 +1848,25 @@ void memory_region_clear_flush_coalesced(MemoryRegion *mr); * @match_data: whether to match against @data, instead of just @addr * @data: the data to match against the guest write * @e: event notifier to be triggered when @addr, @size, and @data all match. + * @transaction: whether to start a transaction for the change **/ -void memory_region_add_eventfd(MemoryRegion *mr, - hwaddr addr, - unsigned size, - bool match_data, - uint64_t data, - EventNotifier *e); +void memory_region_add_eventfd_full(MemoryRegion *mr, + hwaddr addr, + unsigned size, + bool match_data, + uint64_t data, + EventNotifier *e, + bool transaction); + +static inline void memory_region_add_eventfd(MemoryRegion *mr, + hwaddr addr, + unsigned size, + bool match_data, + uint64_t data, + EventNotifier *e) +{ + memory_region_add_eventfd_full(mr, addr, size, match_data, data, e, true); +} /** * memory_region_del_eventfd: Cancel an eventfd. @@ -1868,13 +1880,25 @@ void memory_region_add_eventfd(MemoryRegion *mr, * @match_data: whether to match against @data, instead of just @addr * @data: the data to match against the guest write * @e: event notifier to be triggered when @addr, @size, and @data all match. + * @transaction: whether to start a transaction for the change */ -void memory_region_del_eventfd(MemoryRegion *mr, - hwaddr addr, - unsigned size, - bool match_data, - uint64_t data, - EventNotifier *e); +void memory_region_del_eventfd_full(MemoryRegion *mr, + hwaddr addr, + unsigned size, + bool match_data, + uint64_t data, + EventNotifier *e, + bool transaction); + +static inline void memory_region_del_eventfd(MemoryRegion *mr, + hwaddr addr, + unsigned size, + bool match_data, + uint64_t data, + EventNotifier *e) +{ + memory_region_del_eventfd_full(mr, addr, size, match_data, data, e, true); +} /** * memory_region_add_subregion: Add a subregion to a container. diff --git a/softmmu/memory.c b/softmmu/memory.c index d4493ef9e430..1b1942d521cc 100644 --- a/softmmu/memory.c +++ b/softmmu/memory.c @@ -2341,12 +2341,13 @@ void memory_region_clear_flush_coalesced(MemoryRegion *mr) static bool userspace_eventfd_warning; -void memory_region_add_eventfd(MemoryRegion *mr, - hwaddr addr, - unsigned size, - bool match_data, - uint64_t data, - EventNotifier *e) +void memory_region_add_eventfd_full(MemoryRegion *mr, + hwaddr addr, + unsigned size, + bool match_data, + uint64_t data, + EventNotifier *e, + bool transaction) { MemoryRegionIoeventfd mrfd = { .addr.start = int128_make64(addr), @@ -2367,7 +2368,9 @@ void memory_region_add_eventfd(MemoryRegion *mr, if (size) { adjust_endianness(mr, &mrfd.data, size_memop(size) | MO_TE); } - memory_region_transaction_begin(); + if (transaction) { + memory_region_transaction_begin(); + } for (i = 0; i < mr->ioeventfd_nb; ++i) { if (memory_region_ioeventfd_before(&mrfd, &mr->ioeventfds[i])) { break; @@ -2380,15 +2383,18 @@ void memory_region_add_eventfd(MemoryRegion *mr, sizeof(*mr->ioeventfds) * (mr->ioeventfd_nb-1 - i)); mr->ioeventfds[i] = mrfd; ioeventfd_update_pending |= mr->enabled; - memory_region_transaction_commit(); + if (transaction) { + memory_region_transaction_commit(); + } } -void memory_region_del_eventfd(MemoryRegion *mr, - hwaddr addr, - unsigned size, - bool match_data, - uint64_t data, - EventNotifier *e) +void memory_region_del_eventfd_full(MemoryRegion *mr, + hwaddr addr, + unsigned size, + bool match_data, + uint64_t data, + EventNotifier *e, + bool transaction) { MemoryRegionIoeventfd mrfd = { .addr.start = int128_make64(addr), @@ -2402,7 +2408,9 @@ void memory_region_del_eventfd(MemoryRegion *mr, if (size) { adjust_endianness(mr, &mrfd.data, size_memop(size) | MO_TE); } - memory_region_transaction_begin(); + if (transaction) { + memory_region_transaction_begin(); + } for (i = 0; i < mr->ioeventfd_nb; ++i) { if (memory_region_ioeventfd_equal(&mrfd, &mr->ioeventfds[i])) { break; @@ -2415,7 +2423,9 @@ void memory_region_del_eventfd(MemoryRegion *mr, mr->ioeventfds = g_realloc(mr->ioeventfds, sizeof(*mr->ioeventfds)*mr->ioeventfd_nb + 1); ioeventfd_update_pending |= mr->enabled; - memory_region_transaction_commit(); + if (transaction) { + memory_region_transaction_commit(); + } } static void memory_region_update_container_subregions(MemoryRegion *subregion) -- 2.26.3