mirror of
https://git.proxmox.com/git/qemu
synced 2025-08-13 13:24:04 +00:00
vhost: optimize out no-change assignment
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 <mst@redhat.com>
This commit is contained in:
parent
f5a4e64f8e
commit
4e789564d3
54
hw/vhost.c
54
hw/vhost.c
@ -297,6 +297,45 @@ static int vhost_verify_ring_mappings(struct vhost_dev *dev,
|
|||||||
return 0;
|
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,
|
static void vhost_client_set_memory(CPUPhysMemoryClient *client,
|
||||||
target_phys_addr_t start_addr,
|
target_phys_addr_t start_addr,
|
||||||
ram_addr_t size,
|
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];
|
(dev->mem->nregions + 1) * sizeof dev->mem->regions[0];
|
||||||
uint64_t log_size;
|
uint64_t log_size;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
dev->mem = qemu_realloc(dev->mem, s);
|
dev->mem = qemu_realloc(dev->mem, s);
|
||||||
|
|
||||||
if (log_dirty) {
|
if (log_dirty) {
|
||||||
@ -317,6 +357,20 @@ static void vhost_client_set_memory(CPUPhysMemoryClient *client,
|
|||||||
|
|
||||||
assert(size);
|
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);
|
vhost_dev_unassign_memory(dev, start_addr, size);
|
||||||
if (flags == IO_MEM_RAM) {
|
if (flags == IO_MEM_RAM) {
|
||||||
/* Add given mapping, merging adjacent regions if any */
|
/* Add given mapping, merging adjacent regions if any */
|
||||||
|
Loading…
Reference in New Issue
Block a user