RE: [RFC]Two ideas to optimize updating irq routing table

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



> > Based on discussions in:
> > http://lists.gnu.org/archive/html/qemu-devel/2013-11/threads.html#03322
> >
> > About KVM_SET_GSI_ROUTING ioctl, I tested changing RCU to SRCU, but
> unfortunately
> > it looks like SRCU's grace period is no better than RCU.
> 
> Really?  This is not what Christian Borntraeger claimed at
> http://permalink.gmane.org/gmane.comp.emulators.kvm.devel/118083 -- in
> fact, Andrew Theurer is currently testing a variant of that patch and I
> was going to post it for 3.16.
> 
> Have you tried synchronize_srcu_expedited?  Unlike the RCU variant, you
> can use this function.
> 
Yes, previously I was using synchronize_srcu, which is not good. When I 
changed it to synchronize_srcu_expedited, grace period delay is much better 
than synchronize_srcu. Though in our tests, we can still see some impact 
of KVM_SET_GSI_ROUTING ioctl.

Our testing scenario is like this. In VM we run a script that sets smp_affinity 
for each IRQ every 0.5s (this leads QEMU to do KVM_SET_GSI_ROUTING ioctl).
Outside the VM we ping that VM.

Without patches, ping time can jump from 0.3ms to 2ms-30ms. With synchronize_srcu 
patch, ping time is worse. With synchronize_srcu_expedited patch, ping time is 
overall good, though sometimes ping time jump to 1ms-3ms.

With following raw patch, ping time is like call_rcu patch, that not influenced 
by setting IRQ affinity, keeps 0.3ms, and there is no vulnerability, frequent 
intermidiate KVM_SET_GSI_ROUTING settings are just skipped, and always the newest 
setting would take effect.

Would you think this patch is acceptable or has problem? Thanks in advance.

diff -urp kvm_kmod/include/linux/kvm_host.h kvm_kmod_new//include/linux/kvm_host.h
--- kvm_kmod/include/linux/kvm_host.h	2014-03-10 14:08:28.000000000 +0000
+++ kvm_kmod_new//include/linux/kvm_host.h	2014-03-26 15:07:48.000000000 +0000
@@ -337,6 +337,12 @@ struct kvm {
 
 	struct mutex irq_lock;
 #ifdef CONFIG_HAVE_KVM_IRQCHIP
+	struct task_struct *kthread;
+	wait_queue_head_t wq;
+	struct mutex irq_routing_lock;
+	struct kvm_irq_routing to_update_routing;
+	struct kvm_irq_routing_entry *to_update_entries;
+	atomic_t have_new;
 	/*
 	 * Update side is protected by irq_lock and,
 	 * if configured, irqfds.lock.
diff -urp kvm_kmod/x86/assigned-dev.c kvm_kmod_new//x86/assigned-dev.c
--- kvm_kmod/x86/assigned-dev.c	2014-03-10 14:08:28.000000000 +0000
+++ kvm_kmod_new//x86/assigned-dev.c	2014-03-26 15:22:33.000000000 +0000
@@ -1056,12 +1056,23 @@ long kvm_vm_ioctl_assigned_device(struct
 		r = -EFAULT;
 		urouting = argp;
 		if (copy_from_user(entries, urouting->entries,
-				   routing.nr * sizeof(*entries)))
-			goto out_free_irq_routing;
-		r = kvm_set_irq_routing(kvm, entries, routing.nr,
-					routing.flags);
-	out_free_irq_routing:
-		vfree(entries);
+				   routing.nr * sizeof(*entries))) {
+			vfree(entries);
+			break;
+		}
+
+		mutex_lock(&kvm->irq_routing_lock);
+		if (kvm->to_update_entries) {
+			vfree(kvm->to_update_entries);
+			kvm->to_update_entries = NULL;
+		}
+		kvm->to_update_routing = routing;
+		kvm->to_update_entries = entries;
+		atomic_set(&kvm->have_new, 1);
+		mutex_unlock(&kvm->irq_routing_lock);
+
+		wake_up(&kvm->wq);
+		r = 0;  /* parameter validity or memory alloc avalibity should be checked before return */
 		break;
 	}
 #endif /* KVM_CAP_IRQ_ROUTING */
diff -urp kvm_kmod/x86/kvm_main.c kvm_kmod_new//x86/kvm_main.c
--- kvm_kmod/x86/kvm_main.c	2014-03-10 14:08:28.000000000 +0000
+++ kvm_kmod_new//x86/kvm_main.c	2014-03-26 15:27:02.000000000 +0000
@@ -83,6 +83,7 @@
 #include <linux/slab.h>
 #include <linux/sort.h>
 #include <linux/bsearch.h>
+#include <linux/kthread.h>
 
 #include <asm/processor.h>
 #include <asm/io.h>
@@ -501,6 +502,49 @@ static void kvm_init_memslots_id(struct
 		slots->id_to_index[i] = slots->memslots[i].id = i;
 }
 
+static int do_irq_routing_table_update(struct kvm *kvm)
+{
+	struct kvm_irq_routing_entry *entries;
+	unsigned nr;
+	unsigned flags;
+
+	mutex_lock(&kvm->irq_routing_lock);
+	BUG_ON(!kvm->to_update_entries);
+
+	nr = kvm->to_update_routing.nr;
+	flags = kvm->to_update_routing.flags;
+	entries = vmalloc(nr * sizeof(*entries));
+	if (!entries) {
+		mutex_unlock(&kvm->irq_routing_lock);
+	        return 0;
+	}
+       /* this memcpy can be eliminated by doing set in mutex_lock and doing synchronize_rcu outside */
+	memcpy(entries, kvm->to_update_entries, nr * sizeof(*entries));
+
+	atomic_set(&kvm->have_new, 0);
+	mutex_unlock(&kvm->irq_routing_lock);
+
+	kvm_set_irq_routing(kvm, entries, nr, flags);
+
+	return 0;
+}
+
+static int do_irq_routing_rcu(void *data)
+{
+	struct kvm *kvm = (struct kvm *)data;
+
+	while (1) {
+		wait_event_interruptible(kvm->wq,
+			atomic_read(&kvm->have_new) || kthread_should_stop());
+
+		if (kthread_should_stop())
+			break;
+
+		do_irq_routing_table_update(kvm);
+	}
+
+	return 0;
+}
+
 static struct kvm *kvm_create_vm(unsigned long type)
 {
 	int r, i;
@@ -529,6 +573,12 @@ static struct kvm *kvm_create_vm(unsigne
 	kvm_init_memslots_id(kvm);
 	if (init_srcu_struct(&kvm->srcu))
 		goto out_err_nosrcu;
+
+	atomic_set(&kvm->have_new, 0);
+	init_waitqueue_head(&kvm->wq);
+	mutex_init(&kvm->irq_routing_lock);
+	kvm->kthread = kthread_run(do_irq_routing_rcu, kvm, "irq_routing");
+
 	for (i = 0; i < KVM_NR_BUSES; i++) {
 		kvm->buses[i] = kzalloc(sizeof(struct kvm_io_bus),
 					GFP_KERNEL);
@@ -635,6 +685,11 @@ static void kvm_destroy_vm(struct kvm *k
 	list_del(&kvm->vm_list);
 	raw_spin_unlock(&kvm_lock);
 	kvm_free_irq_routing(kvm);
+
+	kthread_stop(kvm->kthread);
+	if (kvm->to_update_entries)
+		vfree(kvm->to_update_entries);
+
 	for (i = 0; i < KVM_NR_BUSES; i++)
 		kvm_io_bus_destroy(kvm->buses[i]);
 	kvm_coalesced_mmio_free(kvm);


Best regards,
-Gonglei
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux