Commit d4c67a7a authored by Gal Hammer's avatar Gal Hammer Committed by Radim Krčmář

kvm: use insert sort in kvm_io_bus_register_dev function

The loading time of a VM is quite significant with a CPU usage
reaching 100% when loading a VM that its virtio devices use a
large amount of virt-queues (e.g. a virtio-serial device with
max_ports=511). Most of the time is spend in re-sorting the
kvm_io_bus kvm_io_range array when a new eventfd is registered.

The patch replaces the existing method with an insert sort.
Reviewed-by: default avatarMarcel Apfelbaum <marcel@redhat.com>
Reviewed-by: default avatarUri Lublin <ulublin@redhat.com>
Signed-off-by: default avatarGal Hammer <ghammer@redhat.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
Signed-off-by: default avatarRadim Krčmář <rkrcmar@redhat.com>
parent 01643c51
...@@ -3398,21 +3398,6 @@ static int kvm_io_bus_sort_cmp(const void *p1, const void *p2) ...@@ -3398,21 +3398,6 @@ static int kvm_io_bus_sort_cmp(const void *p1, const void *p2)
return kvm_io_bus_cmp(p1, p2); return kvm_io_bus_cmp(p1, p2);
} }
static int kvm_io_bus_insert_dev(struct kvm_io_bus *bus, struct kvm_io_device *dev,
gpa_t addr, int len)
{
bus->range[bus->dev_count++] = (struct kvm_io_range) {
.addr = addr,
.len = len,
.dev = dev,
};
sort(bus->range, bus->dev_count, sizeof(struct kvm_io_range),
kvm_io_bus_sort_cmp, NULL);
return 0;
}
static int kvm_io_bus_get_first_dev(struct kvm_io_bus *bus, static int kvm_io_bus_get_first_dev(struct kvm_io_bus *bus,
gpa_t addr, int len) gpa_t addr, int len)
{ {
...@@ -3553,7 +3538,9 @@ int kvm_io_bus_read(struct kvm_vcpu *vcpu, enum kvm_bus bus_idx, gpa_t addr, ...@@ -3553,7 +3538,9 @@ int kvm_io_bus_read(struct kvm_vcpu *vcpu, enum kvm_bus bus_idx, gpa_t addr,
int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr, int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
int len, struct kvm_io_device *dev) int len, struct kvm_io_device *dev)
{ {
int i;
struct kvm_io_bus *new_bus, *bus; struct kvm_io_bus *new_bus, *bus;
struct kvm_io_range range;
bus = kvm_get_bus(kvm, bus_idx); bus = kvm_get_bus(kvm, bus_idx);
if (!bus) if (!bus)
...@@ -3567,9 +3554,22 @@ int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr, ...@@ -3567,9 +3554,22 @@ int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
sizeof(struct kvm_io_range)), GFP_KERNEL); sizeof(struct kvm_io_range)), GFP_KERNEL);
if (!new_bus) if (!new_bus)
return -ENOMEM; return -ENOMEM;
memcpy(new_bus, bus, sizeof(*bus) + (bus->dev_count *
sizeof(struct kvm_io_range))); range = (struct kvm_io_range) {
kvm_io_bus_insert_dev(new_bus, dev, addr, len); .addr = addr,
.len = len,
.dev = dev,
};
for (i = 0; i < bus->dev_count; i++)
if (kvm_io_bus_cmp(&bus->range[i], &range) > 0)
break;
memcpy(new_bus, bus, sizeof(*bus) + i * sizeof(struct kvm_io_range));
new_bus->dev_count++;
new_bus->range[i] = range;
memcpy(new_bus->range + i + 1, bus->range + i,
(bus->dev_count - i) * sizeof(struct kvm_io_range));
rcu_assign_pointer(kvm->buses[bus_idx], new_bus); rcu_assign_pointer(kvm->buses[bus_idx], new_bus);
synchronize_srcu_expedited(&kvm->srcu); synchronize_srcu_expedited(&kvm->srcu);
kfree(bus); kfree(bus);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment