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;
|
||||
}
|
||||
|
||||
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 */
|
||||
|
Loading…
Reference in New Issue
Block a user