mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-01 10:43:43 +00:00
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: Marcel Apfelbaum <marcel@redhat.com> Reviewed-by: Uri Lublin <ulublin@redhat.com> Signed-off-by: Gal Hammer <ghammer@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Radim Krčmář <rkrcmar@redhat.com>
This commit is contained in:
parent
01643c51bf
commit
d4c67a7a54
@ -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,
|
|||||||
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,
|
|||||||
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);
|
||||||
|
Loading…
Reference in New Issue
Block a user