From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from [140.186.70.92] (port=49370 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Q7mrT-0006FF-JL for qemu-devel@nongnu.org; Thu, 07 Apr 2011 06:54:53 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Q7mrN-0007XR-LD for qemu-devel@nongnu.org; Thu, 07 Apr 2011 06:54:47 -0400 Received: from mx1.redhat.com ([209.132.183.28]:65032) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Q7mrN-0007X5-CA for qemu-devel@nongnu.org; Thu, 07 Apr 2011 06:54:45 -0400 Date: Thu, 7 Apr 2011 13:54:26 +0300 From: "Michael S. Tsirkin" Message-ID: <4e789564d30a9c5f9408657857560a88386b0ac4.1302173640.git.mst@redhat.com> References: MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: Subject: [Qemu-devel] [PATCH 4/5] vhost: optimize out no-change assignment List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cirrus VGA (at least) calls register memory region with the same values again and again. The registration in vhost-net slows this a lot, optimize by checking that the same data is already registered. Signed-off-by: Michael S. Tsirkin --- hw/vhost.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 54 insertions(+), 0 deletions(-) diff --git a/hw/vhost.c b/hw/vhost.c index 257e3dd..80f771e 100644 --- a/hw/vhost.c +++ b/hw/vhost.c @@ -297,6 +297,45 @@ static int vhost_verify_ring_mappings(struct vhost_dev *dev, return 0; } +static struct vhost_memory_region *vhost_dev_find_reg(struct vhost_dev *dev, + uint64_t start_addr, + uint64_t size) +{ + int i, n = dev->mem->nregions; + for (i = 0; i < n; ++i) { + struct vhost_memory_region *reg = dev->mem->regions + i; + if (ranges_overlap(reg->guest_phys_addr, reg->memory_size, + start_addr, size)) { + return reg; + } + } + return NULL; +} + +static bool vhost_dev_cmp_memory(struct vhost_dev *dev, + uint64_t start_addr, + uint64_t size, + uint64_t uaddr) +{ + struct vhost_memory_region *reg = vhost_dev_find_reg(dev, start_addr, size); + uint64_t reglast; + uint64_t memlast; + + if (!reg) { + return true; + } + + reglast = range_get_last(reg->guest_phys_addr, reg->memory_size); + memlast = range_get_last(start_addr, size); + + /* Need to extend region? */ + if (start_addr < reg->guest_phys_addr || memlast > reglast) { + return true; + } + /* userspace_addr changed? */ + return uaddr != reg->userspace_addr + start_addr - reg->guest_phys_addr; +} + static void vhost_client_set_memory(CPUPhysMemoryClient *client, target_phys_addr_t start_addr, ram_addr_t size, @@ -309,6 +348,7 @@ static void vhost_client_set_memory(CPUPhysMemoryClient *client, (dev->mem->nregions + 1) * sizeof dev->mem->regions[0]; uint64_t log_size; int r; + dev->mem = qemu_realloc(dev->mem, s); if (log_dirty) { @@ -317,6 +357,20 @@ static void vhost_client_set_memory(CPUPhysMemoryClient *client, assert(size); + /* Optimize no-change case. At least cirrus_vga does this a lot at this time. */ + if (flags == IO_MEM_RAM) { + if (!vhost_dev_cmp_memory(dev, start_addr, size, + (uintptr_t)qemu_get_ram_ptr(phys_offset))) { + /* Region exists with same address. Nothing to do. */ + return; + } + } else { + if (!vhost_dev_find_reg(dev, start_addr, size)) { + /* Removing region that we don't access. Nothing to do. */ + return; + } + } + vhost_dev_unassign_memory(dev, start_addr, size); if (flags == IO_MEM_RAM) { /* Add given mapping, merging adjacent regions if any */ -- 1.7.3.2.91.g446ac