aboutsummaryrefslogtreecommitdiff
path: root/virt/kvm/kvm_main.c
diff options
context:
space:
mode:
authorGal Hammer <ghammer@redhat.com>2018-01-16 15:34:41 +0200
committerRadim Krčmář <rkrcmar@redhat.com>2018-03-06 18:40:44 +0100
commitd4c67a7a54f12cb8d267284212f1072c95917e5a (patch)
treebdd2a438fbbb884a45a6fb0ec82f1e9404516c4c /virt/kvm/kvm_main.c
parent01643c51bfcf2460b530854046f62ce1b29713ab (diff)
downloadlinux-d4c67a7a54f12cb8d267284212f1072c95917e5a.tar.gz
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>
Diffstat (limited to 'virt/kvm/kvm_main.c')
-rw-r--r--virt/kvm/kvm_main.c36
1 files changed, 18 insertions, 18 deletions
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 65dea3ffef68..c7b2e927f699 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -3398,21 +3398,6 @@ static int kvm_io_bus_sort_cmp(const void *p1, const void *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,
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 len, struct kvm_io_device *dev)
{
+ int i;
struct kvm_io_bus *new_bus, *bus;
+ struct kvm_io_range range;
bus = kvm_get_bus(kvm, bus_idx);
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);
if (!new_bus)
return -ENOMEM;
- memcpy(new_bus, bus, sizeof(*bus) + (bus->dev_count *
- sizeof(struct kvm_io_range)));
- kvm_io_bus_insert_dev(new_bus, dev, addr, len);
+
+ range = (struct kvm_io_range) {
+ .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);
synchronize_srcu_expedited(&kvm->srcu);
kfree(bus);