|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [RFC PATCH v1] Replace tasklets with per-cpu implementation.
On Fri, Aug 29, 2014 at 03:10:19PM +0100, Jan Beulich wrote:
> >>> On 29.08.14 at 15:46, <konrad.wilk@xxxxxxxxxx> wrote:
> > On Thu, Aug 28, 2014 at 01:39:54PM +0100, Jan Beulich wrote:
> >> >>> On 27.08.14 at 19:58, <konrad.wilk@xxxxxxxxxx> wrote:
> >> > The 'hvm_do_IRQ_dpci' is the on that is most often scheduled
> >> > and run. The performance bottleneck comes from the fact that
> >> > we take the same spinlock three times: tasklet_schedule,
> >> > when we are about to execute the tasklet, and when we are
> >> > done executing the tasklet.
> >>
> >> Before starting all the work here, did you investigate alternatives
> >> to this specific use of a tasklet? E.g., it being a softirq one, making
> >> it have its own softirq?
> >
> > If I understand you right, you mean implement an tasklet API that
> > would only been be used by the hvm_do_IRQ_dpci? Its own spinlock,
> > list, and an seperate tasklet_schedule?
>
> No, just a new softirq type, e.g. HVM_DPCI_SOFTIRQ (added to
> the enum in xen/include/xen/softirq.h and all the necessary
> handling put in place).
I typed this prototype up and asked folks with the right hardware to
test it. It _ought_ to, thought I think that the tasklet code
still could use an overhaul.
From deecf148e0061027c61af30882eee76a66299686 Mon Sep 17 00:00:00 2001
From: Konrad Rzeszutek Wilk <konrad.wilk@xxxxxxxxxx>
Date: Fri, 29 Aug 2014 13:40:09 -0400
Subject: [PATCH] dpci: Replace tasklet with an softirq
PROTOTYPE.
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@xxxxxxxxxx>
---
xen/drivers/passthrough/io.c | 149 ++++++++++++++++++++++++++++++++++++++++--
xen/drivers/passthrough/pci.c | 5 +-
xen/include/xen/hvm/irq.h | 3 +
xen/include/xen/sched.h | 3 +
xen/include/xen/softirq.h | 1 +
5 files changed, 156 insertions(+), 5 deletions(-)
diff --git a/xen/drivers/passthrough/io.c b/xen/drivers/passthrough/io.c
index c83af68..4c8ff3b 100644
--- a/xen/drivers/passthrough/io.c
+++ b/xen/drivers/passthrough/io.c
@@ -26,10 +26,105 @@
#include <xen/hvm/irq.h>
#include <xen/tasklet.h>
+bool_t use_softirq;
+boolean_param("use_softirq", use_softirq);
+
struct rangeset *__read_mostly mmio_ro_ranges;
static void hvm_dirq_assist(unsigned long _d);
+static DEFINE_PER_CPU(struct list_head, dpci_list);
+
+enum {
+ STATE_SCHED,
+ STATE_RUN
+};
+static void schedule_dpci_for(struct domain *d)
+{
+ if ( !test_and_set_bit(STATE_SCHED, &d->state) )
+ {
+ unsigned long flags;
+ struct list_head *list;
+
+ local_irq_save(flags);
+ INIT_LIST_HEAD(&d->list);
+ list = &__get_cpu_var(dpci_list);
+ list_add_tail(&d->list, list);
+
+ local_irq_restore(flags);
+ raise_softirq(HVM_DPCI_SOFTIRQ);
+ }
+}
+
+void dpci_kill(struct domain *d)
+{
+ s_time_t s, now;
+ int i = 0;
+
+ s = NOW();
+ while ( test_and_set_bit(STATE_SCHED, &d->state) )
+ {
+ do {
+ now = NOW();
+ process_pending_softirqs();
+ if ( ((now - s) >> 30) > 5 )
+ {
+ s = now;
+ printk("%s stuck .. \n", __func__);
+ i++;
+ }
+ if ( i > 12 )
+ BUG();
+ } while ( test_bit(STATE_SCHED, &d->state) );
+ }
+ while (test_bit(STATE_RUN, &(d)->state))
+ {
+ cpu_relax();
+ }
+ clear_bit(STATE_SCHED, &d->state);
+}
+
+static void dpci_softirq(void)
+{
+
+ struct domain *d;
+ struct list_head *list;
+ struct list_head our_list;
+
+ local_irq_disable();
+ list = &__get_cpu_var(dpci_list);
+
+ INIT_LIST_HEAD(&our_list);
+ list_splice(list, &our_list);
+
+ INIT_LIST_HEAD(&__get_cpu_var(dpci_list));
+
+ local_irq_enable();
+
+ while (!list_empty(&our_list))
+ {
+ d = list_entry(our_list.next, struct domain, list);
+ list_del(&d->list);
+
+ if ( !test_and_set_bit(STATE_RUN, &(d)->state) )
+ {
+ if ( !test_and_clear_bit(STATE_SCHED, &d->state) )
+ BUG();
+ hvm_dirq_assist((unsigned long)d);
+ clear_bit(STATE_RUN, &(d)->state);
+ continue;
+ }
+
+ local_irq_disable();
+
+ INIT_LIST_HEAD(&d->list);
+ list_add_tail(&d->list, &__get_cpu_var(dpci_list));
+ local_irq_enable();
+
+ raise_softirq(HVM_DPCI_SOFTIRQ);
+ }
+}
+
bool_t pt_irq_need_timer(uint32_t flags)
{
return !(flags & (HVM_IRQ_DPCI_GUEST_MSI | HVM_IRQ_DPCI_TRANSLATE));
@@ -119,9 +214,13 @@ int pt_irq_create_bind_vtd(
return -ENOMEM;
}
memset(hvm_irq_dpci, 0, sizeof(*hvm_irq_dpci));
- percpu_tasklet_init(
- &hvm_irq_dpci->dirq_tasklet,
- hvm_dirq_assist, (unsigned long)d);
+ if ( !use_softirq )
+ percpu_tasklet_init(
+ &hvm_irq_dpci->dirq_tasklet,
+ hvm_dirq_assist, (unsigned long)d);
+ else
+ printk("%s: Using HVM_DPCI_SOFTIRQ for d%d.\n", __func__,
d->domain_id);
+
hvm_irq_dpci->mirq = xmalloc_array(struct hvm_mirq_dpci_mapping,
d->nr_pirqs);
hvm_irq_dpci->dirq_mask = xmalloc_array(unsigned long,
@@ -398,7 +497,10 @@ int hvm_do_IRQ_dpci(struct domain *d, unsigned int mirq)
return 0;
set_bit(mirq, dpci->dirq_mask);
- tasklet_schedule(&dpci->dirq_tasklet);
+ if ( !use_softirq )
+ tasklet_schedule(&dpci->dirq_tasklet);
+ else
+ schedule_dpci_for(d);
return 1;
}
@@ -574,11 +676,50 @@ void hvm_dpci_eoi(struct domain *d, unsigned int
guest_gsi,
unlock:
spin_unlock(&d->event_lock);
}
+#include <xen/cpu.h>
+static int cpu_callback(
+ struct notifier_block *nfb, unsigned long action, void *hcpu)
+{
+ unsigned int cpu = (unsigned long)hcpu;
+
+ printk("%s for CPU%d\n", __func__, cpu);
+
+ switch ( action )
+ {
+ case CPU_UP_PREPARE:
+ INIT_LIST_HEAD(&per_cpu(dpci_list, cpu));
+ break;
+ case CPU_UP_CANCELED:
+ case CPU_DEAD:
+ BUG(); /* To implement. */
+ break;
+ default:
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block cpu_nfb = {
+ .notifier_call = cpu_callback,
+ .priority = 99
+};
static int __init setup_mmio_ro_ranges(void)
{
mmio_ro_ranges = rangeset_new(NULL, "r/o mmio ranges",
RANGESETF_prettyprint_hex);
+ printk("HVM_DPCI_SOFTIRQ is %s\n", use_softirq ? "active" : "offline");
+ if ( use_softirq )
+ {
+ int cpu;
+
+ for_each_online_cpu(cpu)
+ INIT_LIST_HEAD(&per_cpu(dpci_list, cpu));
+
+ open_softirq(HVM_DPCI_SOFTIRQ, dpci_softirq);
+ register_cpu_notifier(&cpu_nfb);
+ }
return 0;
}
__initcall(setup_mmio_ro_ranges);
diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c
index 111ac96..24900da 100644
--- a/xen/drivers/passthrough/pci.c
+++ b/xen/drivers/passthrough/pci.c
@@ -296,7 +296,10 @@ static void pci_clean_dpci_irqs(struct domain *d)
hvm_irq_dpci = domain_get_irq_dpci(d);
if ( hvm_irq_dpci != NULL )
{
- tasklet_kill(&hvm_irq_dpci->dirq_tasklet);
+ if ( !use_softirq )
+ tasklet_kill(&hvm_irq_dpci->dirq_tasklet);
+ else
+ dpci_kill(d);
for ( i = find_first_bit(hvm_irq_dpci->mapping, d->nr_pirqs);
i < d->nr_pirqs;
diff --git a/xen/include/xen/hvm/irq.h b/xen/include/xen/hvm/irq.h
index f21b02c..340293c 100644
--- a/xen/include/xen/hvm/irq.h
+++ b/xen/include/xen/hvm/irq.h
@@ -102,6 +102,9 @@ struct hvm_irq_dpci {
struct tasklet dirq_tasklet;
};
+extern bool_t use_softirq;
+void dpci_kill(struct domain *d);
+
/* Modify state of a PCI INTx wire. */
void hvm_pci_intx_assert(
struct domain *d, unsigned int device, unsigned int intx);
diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
index c04b25d..ba9982e 100644
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -332,6 +332,9 @@ struct domain
nodemask_t node_affinity;
unsigned int last_alloc_node;
spinlock_t node_affinity_lock;
+ /* For HVM_DPCI_SOFTIRQ. Locking is bit wonky. */
+ struct list_head list;
+ unsigned long state;
};
struct domain_setup_info
diff --git a/xen/include/xen/softirq.h b/xen/include/xen/softirq.h
index c5b429c..7134727 100644
--- a/xen/include/xen/softirq.h
+++ b/xen/include/xen/softirq.h
@@ -9,6 +9,7 @@ enum {
RCU_SOFTIRQ,
TASKLET_SOFTIRQ_PERCPU,
TASKLET_SOFTIRQ,
+ HVM_DPCI_SOFTIRQ,
NR_COMMON_SOFTIRQS
};
--
1.9.3
>
> Jan
>
>
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |