From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from [140.186.70.92] (port=49064 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Q7ZZ1-0003dy-Tk for qemu-devel@nongnu.org; Wed, 06 Apr 2011 16:43:24 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Q7ZYN-00020Q-Dk for qemu-devel@nongnu.org; Wed, 06 Apr 2011 16:42:16 -0400 Received: from mx1.redhat.com ([209.132.183.28]:25540) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Q7ZYN-00020G-47 for qemu-devel@nongnu.org; Wed, 06 Apr 2011 16:42:15 -0400 Date: Wed, 6 Apr 2011 23:41:56 +0300 From: "Michael S. Tsirkin" Message-ID: <075d38642f7595ba01525e7ac8724510a0bf708c.1302121974.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 RFC 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..ff8fc1f 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,21 @@ static void vhost_client_set_memory(CPUPhysMemoryClient *client, (dev->mem->nregions + 1) * sizeof dev->mem->regions[0]; uint64_t log_size; int r; + + /* 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; + } + } + dev->mem = qemu_realloc(dev->mem, s); if (log_dirty) { -- 1.7.3.2.91.g446ac