From nobody Sun Feb 8 18:29:06 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1503604157875793.3771997135096; Thu, 24 Aug 2017 12:49:17 -0700 (PDT) Received: from localhost ([::1]:50214 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dky7w-0004bb-Fl for importer@patchew.org; Thu, 24 Aug 2017 15:49:16 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:52985) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dkxpL-0003nO-L2 for qemu-devel@nongnu.org; Thu, 24 Aug 2017 15:30:06 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dkxpI-0005gM-Dt for qemu-devel@nongnu.org; Thu, 24 Aug 2017 15:30:03 -0400 Received: from mx1.redhat.com ([209.132.183.28]:53380) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dkxpI-0005ft-4m for qemu-devel@nongnu.org; Thu, 24 Aug 2017 15:30:00 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 29BA1883C3; Thu, 24 Aug 2017 19:29:59 +0000 (UTC) Received: from dgilbert-t530.redhat.com (ovpn-117-165.ams2.redhat.com [10.36.117.165]) by smtp.corp.redhat.com (Postfix) with ESMTP id E52907F383; Thu, 24 Aug 2017 19:29:56 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 29BA1883C3 Authentication-Results: ext-mx02.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx02.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=dgilbert@redhat.com From: "Dr. David Alan Gilbert (git)" To: qemu-devel@nongnu.org, maxime.coquelin@redhat.com, a.perevalov@samsung.com, mst@redhat.com, marcandre.lureau@redhat.com Date: Thu, 24 Aug 2017 20:27:28 +0100 Message-Id: <20170824192730.8440-31-dgilbert@redhat.com> In-Reply-To: <20170824192730.8440-1-dgilbert@redhat.com> References: <20170824192730.8440-1-dgilbert@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.26]); Thu, 24 Aug 2017 19:29:59 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC v2 30/32] vhost: Merge neighbouring hugepage regions where appropriate X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: lvivier@redhat.com, aarcange@redhat.com, felipe@nutanix.com, peterx@redhat.com, quintela@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: "Dr. David Alan Gilbert" Where two regions are created with a gap such that when aligned to hugepage boundaries, the two regions overlap, merge them. I also add quite a few trace events to see what's going on. Note: This doesn't handle all the cases, but does handle the common case on a PC due to the 640k hole. Signed-off-by: Dr. David Alan Gilbert Signed-off-by: Maxime Coquelin --- hw/virtio/trace-events | 11 +++++++ hw/virtio/vhost.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++= +++- 2 files changed, 89 insertions(+), 1 deletion(-) diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index 5b599617a1..f98efb39fd 100644 --- a/hw/virtio/trace-events +++ b/hw/virtio/trace-events @@ -1,5 +1,16 @@ # See docs/devel/tracing.txt for syntax documentation. =20 +# hw/virtio/vhost.c +vhost_dev_assign_memory_merged(int from, int to, uint64_t size, uint64_t s= tart_addr, uint64_t uaddr) "f/t=3D%d/%d 0x%"PRIx64" @ P: 0x%"PRIx64" U: 0x%= "PRIx64 +vhost_dev_assign_memory_not_merged(uint64_t size, uint64_t start_addr, uin= t64_t uaddr) "0x%"PRIx64" @ P: 0x%"PRIx64" U: 0x%"PRIx64 +vhost_dev_assign_memory_entry(uint64_t size, uint64_t start_addr, uint64_t= uaddr) "0x%"PRIx64" @ P: 0x%"PRIx64" U: 0x%"PRIx64 +vhost_dev_assign_memory_exit(uint32_t nregions) "%"PRId32 +vhost_huge_page_stretch_and_merge_entry(uint32_t nregions) "%"PRId32 +vhost_huge_page_stretch_and_merge_can(void) "" +vhost_huge_page_stretch_and_merge_size_align(int d, uint64_t gpa, uint64_t= align) "%d: gpa: 0x%"PRIx64" align: 0x%"PRIx64 +vhost_huge_page_stretch_and_merge_start_align(int d, uint64_t gpa, uint64_= t align) "%d: gpa: 0x%"PRIx64" align: 0x%"PRIx64 +vhost_section(const char *name, int r) "%s:%d" + # hw/virtio/vhost-user.c vhost_user_postcopy_end_entry(void) "" vhost_user_postcopy_end_exit(void) "" diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 6eddb099b0..fb506e747f 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -27,6 +27,7 @@ #include "hw/virtio/virtio-access.h" #include "migration/blocker.h" #include "sysemu/dma.h" +#include "trace.h" =20 /* enabled until disconnected backend stabilizes */ #define _VHOST_DEBUG 1 @@ -250,6 +251,8 @@ static void vhost_dev_assign_memory(struct vhost_dev *d= ev, { int from, to; struct vhost_memory_region *merged =3D NULL; + trace_vhost_dev_assign_memory_entry(size, start_addr, uaddr); + for (from =3D 0, to =3D 0; from < dev->mem->nregions; ++from, ++to) { struct vhost_memory_region *reg =3D dev->mem->regions + to; uint64_t prlast, urlast; @@ -293,11 +296,13 @@ static void vhost_dev_assign_memory(struct vhost_dev = *dev, uaddr =3D merged->userspace_addr =3D u; start_addr =3D merged->guest_phys_addr =3D s; size =3D merged->memory_size =3D e - s + 1; + trace_vhost_dev_assign_memory_merged(from, to, size, start_addr, u= addr); assert(merged->memory_size); } =20 if (!merged) { struct vhost_memory_region *reg =3D dev->mem->regions + to; + trace_vhost_dev_assign_memory_not_merged(size, start_addr, uaddr); memset(reg, 0, sizeof *reg); reg->memory_size =3D size; assert(reg->memory_size); @@ -307,6 +312,7 @@ static void vhost_dev_assign_memory(struct vhost_dev *d= ev, } assert(to <=3D dev->mem->nregions + 1); dev->mem->nregions =3D to; + trace_vhost_dev_assign_memory_exit(to); } =20 static uint64_t vhost_get_log_size(struct vhost_dev *dev) @@ -610,8 +616,12 @@ static void vhost_set_memory(MemoryListener *listener, =20 static bool vhost_section(MemoryRegionSection *section) { - return memory_region_is_ram(section->mr) && + bool result; + result =3D memory_region_is_ram(section->mr) && !memory_region_is_rom(section->mr); + + trace_vhost_section(section->mr->name, result); + return result; } =20 static void vhost_begin(MemoryListener *listener) @@ -622,6 +632,68 @@ static void vhost_begin(MemoryListener *listener) dev->mem_changed_start_addr =3D -1; } =20 +/* Look for regions that are hugepage backed but not aligned + * and fix them up to be aligned. + * TODO: For now this is just enough to deal with the 640k hole + */ +static bool vhost_huge_page_stretch_and_merge(struct vhost_dev *dev) +{ + int i, j; + bool result =3D true; + trace_vhost_huge_page_stretch_and_merge_entry(dev->mem->nregions); + + for (i =3D 0; i < dev->mem->nregions; i++) { + struct vhost_memory_region *reg =3D dev->mem->regions + i; + ram_addr_t offset; + RAMBlock *rb =3D qemu_ram_block_from_host((void *)reg->userspace_a= ddr, + false, &offset); + size_t pagesize =3D qemu_ram_pagesize(rb); + uint64_t alignage; + alignage =3D reg->guest_phys_addr & (pagesize - 1); + if (alignage) { + + trace_vhost_huge_page_stretch_and_merge_start_align(i, + (uint64_t)reg->guest_phys_= addr, + alignage); + for (j =3D 0; j < dev->mem->nregions; j++) { + struct vhost_memory_region *oreg =3D dev->mem->regions + j; + if (j =3D=3D i) { + continue; + } + + if (oreg->guest_phys_addr =3D=3D + (reg->guest_phys_addr - alignage) && + oreg->userspace_addr =3D=3D + (reg->userspace_addr - alignage)) { + struct vhost_memory_region treg =3D *reg; + trace_vhost_huge_page_stretch_and_merge_can(); + vhost_dev_unassign_memory(dev, oreg->guest_phys_addr, + oreg->memory_size); + vhost_dev_unassign_memory(dev, treg.guest_phys_addr, + treg.memory_size); + vhost_dev_assign_memory(dev, + treg.guest_phys_addr - alignag= e, + treg.memory_size + alignage, + treg.userspace_addr - alignage= ); + return vhost_huge_page_stretch_and_merge(dev); + } + } + } + alignage =3D reg->memory_size & (pagesize - 1); + if (alignage) { + trace_vhost_huge_page_stretch_and_merge_size_align(i, + (uint64_t)reg->guest_phys_a= ddr, + alignage); + /* We ignore this if we find something else to merge, + * so we only return false if we're left with this + */ + result =3D false; + } + } + + return result; +} + static void vhost_commit(MemoryListener *listener) { struct vhost_dev *dev =3D container_of(listener, struct vhost_dev, @@ -641,6 +713,7 @@ static void vhost_commit(MemoryListener *listener) return; } =20 + vhost_huge_page_stretch_and_merge(dev); if (dev->started) { start_addr =3D dev->mem_changed_start_addr; size =3D dev->mem_changed_end_addr - dev->mem_changed_start_addr += 1; @@ -1512,6 +1585,10 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODe= vice *vdev) goto fail_features; } =20 + if (!vhost_huge_page_stretch_and_merge(hdev)) { + VHOST_OPS_DEBUG("vhost_huge_page_stretch_and_merge failed"); + goto fail_mem; + } if (vhost_dev_has_iommu(hdev)) { memory_listener_register(&hdev->iommu_listener, vdev->dma_as); } --=20 2.13.5