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

[Xen-changelog] [linux-2.6.18-xen] Bind different tasks' evtchns to different vcpus of Dom0



# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Date 1189159765 -3600
# Node ID 8d1af6acf74090a1fafc80d02d2feab2da9b7f53
# Parent  9e03bcda005440ec4f216610bccca2295c31c4bb
Bind different tasks' evtchns to different vcpus of Dom0

Currently, all user-space event channels notify Dom0's vcpu0 -- this
is not nice considering scalability. The patch tries to bind different
tasks' evtchns to different vcpus of Dom0 when the bindings are
initialized, and it can also dynamically change the binding if a task
actually gets run on another vcpu for some reason. Tests (Inb and
OLTP) show the patch can improve scalability to some notable degree.

Signed-off-by: Dexuan Cui <dexuan.cui@xxxxxxxxx>
Signed-off-by: Kan Liang <kan.liang@xxxxxxxxx>
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
 drivers/xen/core/evtchn.c   |   19 ++++++--------
 drivers/xen/evtchn/evtchn.c |   59 ++++++++++++++++++++++++++++++++++++++++++++
 include/xen/evtchn.h        |   12 ++++++++
 3 files changed, 80 insertions(+), 10 deletions(-)

diff -r 9e03bcda0054 -r 8d1af6acf740 drivers/xen/core/evtchn.c
--- a/drivers/xen/core/evtchn.c Fri Sep 07 10:24:57 2007 +0100
+++ b/drivers/xen/core/evtchn.c Fri Sep 07 11:09:25 2007 +0100
@@ -125,12 +125,15 @@ static inline unsigned long active_evtch
                ~sh->evtchn_mask[idx]);
 }
 
-static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu)
-{
+void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu)
+{
+       shared_info_t *s = HYPERVISOR_shared_info;
        int irq = evtchn_to_irq[chn];
 
-       BUG_ON(irq == -1);
-       set_native_irq_info(irq, cpumask_of_cpu(cpu));
+       BUG_ON(!test_bit(chn, s->evtchn_mask));
+
+       if (irq != -1)
+               set_native_irq_info(irq, cpumask_of_cpu(cpu));
 
        clear_bit(chn, (unsigned long *)cpu_evtchn_mask[cpu_evtchn[chn]]);
        set_bit(chn, (unsigned long *)cpu_evtchn_mask[cpu]);
@@ -160,10 +163,6 @@ static inline unsigned long active_evtch
                                           unsigned int idx)
 {
        return (sh->evtchn_pending[idx] & ~sh->evtchn_mask[idx]);
-}
-
-static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu)
-{
 }
 
 static void init_evtchn_cpu_bindings(void)
@@ -607,7 +606,7 @@ static void rebind_irq_to_cpu(unsigned i
         * virq or IPI channel, which don't actually need to be rebound. Ignore
         * it, but don't do the xenlinux-level rebind in that case.
         */
-       if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &bind_vcpu) >= 0)
+       if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &bind_vcpu) == 0)
                bind_evtchn_to_cpu(evtchn, tcpu);
 }
 
@@ -626,7 +625,7 @@ int resend_irq_on_evtchn(unsigned int ir
        if (!VALID_EVTCHN(evtchn))
                return 1;
 
-       masked = synch_test_and_set_bit(evtchn, s->evtchn_mask);
+       masked = test_and_set_evtchn_mask(evtchn);
        synch_set_bit(evtchn, s->evtchn_pending);
        if (!masked)
                unmask_evtchn(evtchn);
diff -r 9e03bcda0054 -r 8d1af6acf740 drivers/xen/evtchn/evtchn.c
--- a/drivers/xen/evtchn/evtchn.c       Fri Sep 07 10:24:57 2007 +0100
+++ b/drivers/xen/evtchn/evtchn.c       Fri Sep 07 11:09:25 2007 +0100
@@ -62,6 +62,9 @@ struct per_user_data {
        /* Processes wait on this queue when ring is empty. */
        wait_queue_head_t evtchn_wait;
        struct fasync_struct *evtchn_async_queue;
+
+       int bind_cpu;
+       int nr_event_wrong_delivery;
 };
 
 /* Who's bound to each port? */
@@ -93,6 +96,45 @@ void evtchn_device_upcall(int port)
        spin_unlock(&port_user_lock);
 }
 
+static void evtchn_rebind_cpu(evtchn_port_t port, unsigned int cpu)
+{
+       struct evtchn_bind_vcpu ebv = { .port = port, .vcpu = cpu };
+       int masked;
+
+       masked = test_and_set_evtchn_mask(port);
+       if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &ebv) == 0)
+               bind_evtchn_to_cpu(port, cpu);
+       if (!masked)
+               unmask_evtchn(port);
+}
+
+static void evtchn_check_wrong_delivery(struct per_user_data *u)
+{
+       evtchn_port_t port;
+       unsigned int current_cpu = smp_processor_id();
+
+       /* Delivered to correct CPU? All is good. */
+       if (u->bind_cpu == current_cpu) {
+               u->nr_event_wrong_delivery = 0;
+               return;
+       }
+
+       /* Tolerate up to 100 consecutive misdeliveries. */
+       if (++u->nr_event_wrong_delivery < 100)
+               return;
+
+       spin_lock_irq(&port_user_lock);
+
+       for (port = 0; port < NR_EVENT_CHANNELS; port++)
+               if (port_user[port] == u)
+                       evtchn_rebind_cpu(port, current_cpu);
+
+       u->bind_cpu = current_cpu;
+       u->nr_event_wrong_delivery = 0;
+
+       spin_unlock_irq(&port_user_lock);
+}
+
 static ssize_t evtchn_read(struct file *file, char __user *buf,
                           size_t count, loff_t *ppos)
 {
@@ -153,6 +195,8 @@ static ssize_t evtchn_read(struct file *
            ((bytes2 != 0) &&
             copy_to_user(&buf[bytes1], &u->ring[0], bytes2)))
                goto unlock_out;
+       
+       evtchn_check_wrong_delivery(u);
 
        u->ring_cons += (bytes1 + bytes2) / sizeof(evtchn_port_t);
        rc = bytes1 + bytes2;
@@ -202,9 +246,22 @@ static void evtchn_bind_to_user(struct p
 static void evtchn_bind_to_user(struct per_user_data *u, int port)
 {
        spin_lock_irq(&port_user_lock);
+
        BUG_ON(port_user[port] != NULL);
        port_user[port] = u;
+
+       if (u->bind_cpu == -1) {
+               static unsigned int bind_cpu;
+               bind_cpu = next_cpu(bind_cpu, cpu_online_map);
+               if (bind_cpu >= NR_CPUS)
+                       bind_cpu = first_cpu(cpu_online_map);
+               u->bind_cpu = bind_cpu;
+       }
+
+       evtchn_rebind_cpu(port, u->bind_cpu);
+
        unmask_evtchn(port);
+
        spin_unlock_irq(&port_user_lock);
 }
 
@@ -385,6 +442,8 @@ static int evtchn_open(struct inode *ino
        mutex_init(&u->ring_cons_mutex);
 
        filp->private_data = u;
+
+       u->bind_cpu = -1;
 
        return 0;
 }
diff -r 9e03bcda0054 -r 8d1af6acf740 include/xen/evtchn.h
--- a/include/xen/evtchn.h      Fri Sep 07 10:24:57 2007 +0100
+++ b/include/xen/evtchn.h      Fri Sep 07 11:09:25 2007 +0100
@@ -104,6 +104,18 @@ void mask_evtchn(int port);
 void mask_evtchn(int port);
 void unmask_evtchn(int port);
 
+#ifdef CONFIG_SMP
+void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu);
+#else
+#define bind_evtchn_to_cpu(chn, cpu)   ((void)0)
+#endif
+
+static inline int test_and_set_evtchn_mask(int port)
+{
+       shared_info_t *s = HYPERVISOR_shared_info;
+       return synch_test_and_set_bit(port, s->evtchn_mask);
+}
+
 static inline void clear_evtchn(int port)
 {
        shared_info_t *s = HYPERVISOR_shared_info;

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.