* [Pv-ops][PATCH 3/4 v2] Netback: Multiple tasklets support
@ 2010-04-29 14:28 Xu, Dongxiao
2010-05-03 16:06 ` Konrad Rzeszutek Wilk
0 siblings, 1 reply; 4+ messages in thread
From: Xu, Dongxiao @ 2010-04-29 14:28 UTC (permalink / raw)
To: xen-devel@lists.xensource.com; +Cc: Jeremy Fitzhardinge, Steven Smith
[-- Attachment #1: Type: text/plain, Size: 680 bytes --]
Netback: Multiple tasklets support.
Now netback uses one pair of tasklets for Tx/Rx data transaction.
Netback tasklet could only run at one CPU at a time, and it is
used to serve all the netfronts. Therefore it has become a
performance bottle neck. This patch is to use multiple tasklet
pairs to replace the current single pair in dom0.
Assuming that Dom0 has CPUNR VCPUs, we define CPUNR kinds of
tasklets pair (CPUNR for Tx, and CPUNR for Rx). Each pare of
tasklets serve specific group of netfronts. Also for those global
and static variables, we duplicated them for each group in
order to avoid the spinlock.
Signed-off-by: Dongxiao Xu <dongxiao.xu@intel.com>
[-- Attachment #2: 0003-Netback-Multiple-tasklets-support.patch --]
[-- Type: application/octet-stream, Size: 23085 bytes --]
From 3d2abcae3ea3026e161ab651cdc3be8b93375545 Mon Sep 17 00:00:00 2001
From: Dongxiao Xu <dongxiao.xu@intel.com>
Date: Fri, 30 Apr 2010 09:24:34 +0800
Subject: [PATCH] Netback: Multiple tasklets support.
Now netback uses one pair of tasklets for Tx/Rx data transaction.
Netback tasklet could only run at one CPU at a time, and it is
used to serve all the netfronts. Therefore it has become a
performance bottle neck. This patch is to use multiple tasklet
pairs to replace the current single pair in dom0.
Assuming that Dom0 has CPUNR VCPUs, we define CPUNR kinds of
tasklets pair (CPUNR for Tx, and CPUNR for Rx). Each pare of
tasklets serve specific group of netfronts. Also for those global
and static variables, we duplicated them for each group in
order to avoid the spinlock.
Signed-off-by: Dongxiao Xu <dongxiao.xu@intel.com>
---
drivers/xen/netback/common.h | 7 ++
drivers/xen/netback/interface.c | 34 ++++++-
drivers/xen/netback/netback.c | 226 +++++++++++++++++++++++----------------
3 files changed, 172 insertions(+), 95 deletions(-)
diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
index 3b0838c..22257c5 100644
--- a/drivers/xen/netback/common.h
+++ b/drivers/xen/netback/common.h
@@ -58,6 +58,7 @@
struct xen_netif {
/* Unique identifier for this interface. */
domid_t domid;
+ int group;
unsigned int handle;
u8 fe_dev_addr[6];
@@ -287,6 +288,12 @@ struct xen_netbk {
struct netbk_rx_meta meta[NET_RX_RING_SIZE];
spinlock_t net_schedule_list_lock;
+
+ spinlock_t group_operation_lock;
+ int netfront_count;
};
+extern struct xen_netbk *xen_netbk;
+extern int xen_netbk_group_nr;
+
#endif /* __NETIF__BACKEND__COMMON_H__ */
diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
index b23b14d..5bb2cf8 100644
--- a/drivers/xen/netback/interface.c
+++ b/drivers/xen/netback/interface.c
@@ -54,6 +54,33 @@
static unsigned long netbk_queue_length = 32;
module_param_named(queue_length, netbk_queue_length, ulong, 0644);
+static void netbk_add_netif(struct xen_netbk *netbk, int group_nr,
+ struct xen_netif *netif)
+{
+ int i;
+ int min_netfront_count;
+ int min_group = 0;
+ spin_lock(&netbk->group_operation_lock);
+ min_netfront_count = netbk[0].netfront_count;
+ for (i = 0; i < group_nr; i++) {
+ if (netbk[i].netfront_count < min_netfront_count) {
+ min_group = i;
+ min_netfront_count = netbk[i].netfront_count;
+ }
+ }
+
+ netif->group = min_group;
+ netbk[netif->group].netfront_count++;
+ spin_unlock(&netbk->group_operation_lock);
+}
+
+static void netbk_remove_netif(struct xen_netbk *netbk, struct xen_netif *netif)
+{
+ spin_lock(&netbk->group_operation_lock);
+ netbk[netif->group].netfront_count--;
+ spin_unlock(&netbk->group_operation_lock);
+}
+
static void __netif_up(struct xen_netif *netif)
{
enable_irq(netif->irq);
@@ -333,6 +360,8 @@ int netif_map(struct xen_netif *netif, unsigned long tx_ring_ref,
if (netif->rx_comms_area == NULL)
goto err_rx;
+ netbk_add_netif(xen_netbk, xen_netbk_group_nr, netif);
+
err = map_frontend_pages(netif, tx_ring_ref, rx_ring_ref);
if (err)
goto err_map;
@@ -366,6 +395,7 @@ int netif_map(struct xen_netif *netif, unsigned long tx_ring_ref,
err_hypervisor:
unmap_frontend_pages(netif);
err_map:
+ netbk_remove_netif(xen_netbk, netif);
free_vm_area(netif->rx_comms_area);
err_rx:
free_vm_area(netif->tx_comms_area);
@@ -378,8 +408,10 @@ void netif_disconnect(struct xen_netif *netif)
rtnl_lock();
netback_carrier_off(netif);
netif_carrier_off(netif->dev); /* discard queued packets */
- if (netif_running(netif->dev))
+ if (netif_running(netif->dev)) {
__netif_down(netif);
+ netbk_remove_netif(xen_netbk, netif);
+ }
rtnl_unlock();
netif_put(netif);
}
diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
index 8e942a1..ae949e4 100644
--- a/drivers/xen/netback/netback.c
+++ b/drivers/xen/netback/netback.c
@@ -49,11 +49,11 @@
/*define NETBE_DEBUG_INTERRUPT*/
-static struct xen_netbk *netbk;
-
+struct xen_netbk *xen_netbk;
+int xen_netbk_group_nr;
static struct page_foreign_tracker *foreign_page_tracker;
-static void netif_idx_release(u16 pending_idx);
+static void netif_idx_release(struct xen_netbk *netbk, u16 pending_idx);
static void make_tx_response(struct xen_netif *netif,
struct xen_netif_tx_request *txp,
s8 st);
@@ -64,18 +64,20 @@ static struct xen_netif_rx_response *make_rx_response(struct xen_netif *netif,
u16 size,
u16 flags);
-static void net_tx_action(unsigned long unused);
+static void net_tx_action(unsigned long data);
-static void net_rx_action(unsigned long unused);
+static void net_rx_action(unsigned long data);
-static inline unsigned long idx_to_pfn(unsigned int idx)
+static inline unsigned long idx_to_pfn(struct xen_netbk *netbk,
+ unsigned int idx)
{
return page_to_pfn(netbk->mmap_pages[idx]);
}
-static inline unsigned long idx_to_kaddr(unsigned int idx)
+static inline unsigned long idx_to_kaddr(struct xen_netbk *netbk,
+ unsigned int idx)
{
- return (unsigned long)pfn_to_kaddr(idx_to_pfn(idx));
+ return (unsigned long)pfn_to_kaddr(idx_to_pfn(netbk, idx));
}
/* extra field used in struct page */
@@ -98,7 +100,7 @@ static inline pending_ring_idx_t pending_index(unsigned i)
return i & (MAX_PENDING_REQS-1);
}
-static inline pending_ring_idx_t nr_pending_reqs(void)
+static inline pending_ring_idx_t nr_pending_reqs(struct xen_netbk *netbk)
{
return MAX_PENDING_REQS -
netbk->pending_prod + netbk->pending_cons;
@@ -111,10 +113,10 @@ MODULE_PARM_DESC(copy_skb, "Copy data received from netfront without netloop");
int netbk_copy_skb_mode;
-static inline void maybe_schedule_tx_action(void)
+static inline void maybe_schedule_tx_action(struct xen_netbk *netbk)
{
smp_mb();
- if ((nr_pending_reqs() < (MAX_PENDING_REQS/2)) &&
+ if ((nr_pending_reqs(netbk) < (MAX_PENDING_REQS/2)) &&
!list_empty(&netbk->net_schedule_list))
tasklet_schedule(&netbk->net_tx_tasklet);
}
@@ -221,6 +223,7 @@ static void tx_queue_callback(unsigned long data)
int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct xen_netif *netif = netdev_priv(dev);
+ struct xen_netbk *netbk = &xen_netbk[netif->group];
BUG_ON(skb->dev != dev);
@@ -406,9 +409,10 @@ static void netbk_add_frag_responses(struct xen_netif *netif, int status,
}
}
-static void net_rx_action(unsigned long unused)
+static void net_rx_action(unsigned long data)
{
struct xen_netif *netif = NULL;
+ struct xen_netbk *netbk = (struct xen_netbk *)data;
s8 status;
u16 id, irq, flags;
struct xen_netif_rx_response *resp;
@@ -580,13 +584,15 @@ static void net_rx_action(unsigned long unused)
tasklet_schedule(&netbk->net_rx_tasklet);
}
-static void net_alarm(unsigned long unused)
+static void net_alarm(unsigned long data)
{
+ struct xen_netbk *netbk = (struct xen_netbk *)data;
tasklet_schedule(&netbk->net_rx_tasklet);
}
-static void netbk_tx_pending_timeout(unsigned long unused)
+static void netbk_tx_pending_timeout(unsigned long data)
{
+ struct xen_netbk *netbk = (struct xen_netbk *)data;
tasklet_schedule(&netbk->net_tx_tasklet);
}
@@ -603,6 +609,7 @@ static int __on_net_schedule_list(struct xen_netif *netif)
static void remove_from_net_schedule_list(struct xen_netif *netif)
{
+ struct xen_netbk *netbk = &xen_netbk[netif->group];
spin_lock_irq(&netbk->net_schedule_list_lock);
if (likely(__on_net_schedule_list(netif))) {
list_del_init(&netif->list);
@@ -613,6 +620,7 @@ static void remove_from_net_schedule_list(struct xen_netif *netif)
static void add_to_net_schedule_list_tail(struct xen_netif *netif)
{
+ struct xen_netbk *netbk = &xen_netbk[netif->group];
if (__on_net_schedule_list(netif))
return;
@@ -627,13 +635,14 @@ static void add_to_net_schedule_list_tail(struct xen_netif *netif)
void netif_schedule_work(struct xen_netif *netif)
{
+ struct xen_netbk *netbk = &xen_netbk[netif->group];
int more_to_do;
RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, more_to_do);
if (more_to_do) {
add_to_net_schedule_list_tail(netif);
- maybe_schedule_tx_action();
+ maybe_schedule_tx_action(netbk);
}
}
@@ -670,14 +679,15 @@ static void tx_credit_callback(unsigned long data)
netif_schedule_work(netif);
}
-static inline int copy_pending_req(pending_ring_idx_t pending_idx)
+static inline int copy_pending_req(struct xen_netbk *netbk,
+ pending_ring_idx_t pending_idx)
{
return gnttab_copy_grant_page(
netbk->grant_tx_handle[pending_idx],
&netbk->mmap_pages[pending_idx]);
}
-inline static void net_tx_action_dealloc(void)
+static inline void net_tx_action_dealloc(struct xen_netbk *netbk)
{
struct netbk_tx_pending_inuse *inuse, *n;
struct gnttab_unmap_grant_ref *gop;
@@ -707,7 +717,7 @@ inline static void net_tx_action_dealloc(void)
pending_idx = netbk->dealloc_ring[pending_index(dc++)];
list_move_tail(&pending_inuse[pending_idx].list, &list);
- pfn = idx_to_pfn(pending_idx);
+ pfn = idx_to_pfn(netbk, pending_idx);
/* Already unmapped? */
if (!phys_to_machine_mapping_valid(pfn))
continue;
@@ -715,7 +725,7 @@ inline static void net_tx_action_dealloc(void)
stop_tracking_page(netbk->mmap_pages[pending_idx]);
gnttab_set_unmap_op(gop,
- idx_to_kaddr(pending_idx),
+ idx_to_kaddr(netbk, pending_idx),
GNTMAP_host_map,
netbk->grant_tx_handle[pending_idx]);
gop++;
@@ -738,7 +748,7 @@ inline static void net_tx_action_dealloc(void)
pending_tx_info[pending_idx].netif->nr_copied_skbs++;
- switch (copy_pending_req(pending_idx)) {
+ switch (copy_pending_req(netbk, pending_idx)) {
case 0:
list_move_tail(&inuse->list, &list);
continue;
@@ -841,7 +851,8 @@ static int netbk_count_requests(struct xen_netif *netif,
return frags;
}
-static struct gnttab_map_grant_ref *netbk_get_requests(struct xen_netif *netif,
+static struct gnttab_map_grant_ref *netbk_get_requests(struct xen_netbk *netbk,
+ struct xen_netif *netif,
struct sk_buff *skb,
struct xen_netif_tx_request *txp,
struct gnttab_map_grant_ref *mop)
@@ -850,6 +861,7 @@ static struct gnttab_map_grant_ref *netbk_get_requests(struct xen_netif *netif,
skb_frag_t *frags = shinfo->frags;
unsigned long pending_idx = *((u16 *)skb->data);
int i, start;
+ int group = netif->group;
/* Skip first skb fragment if it is on same page as header fragment. */
start = ((unsigned long)shinfo->frags[0].page == pending_idx);
@@ -862,7 +874,7 @@ static struct gnttab_map_grant_ref *netbk_get_requests(struct xen_netif *netif,
index = pending_index(netbk->pending_cons++);
pending_idx = netbk->pending_ring[index];
- gnttab_set_map_op(mop++, idx_to_kaddr(pending_idx),
+ gnttab_set_map_op(mop++, idx_to_kaddr(netbk, pending_idx),
GNTMAP_host_map | GNTMAP_readonly,
txp->gref, netif->domid);
@@ -875,15 +887,16 @@ static struct gnttab_map_grant_ref *netbk_get_requests(struct xen_netif *netif,
netbk->mmap_pages[pending_idx],
netif->domid,
pending_tx_info[pending_idx].req.gref,
- pending_idx,
+ group * MAX_PENDING_REQS + pending_idx,
NULL);
}
return mop;
}
-static int netbk_tx_check_mop(struct sk_buff *skb,
- struct gnttab_map_grant_ref **mopp)
+static int netbk_tx_check_mop(struct xen_netbk *netbk,
+ struct sk_buff *skb,
+ struct gnttab_map_grant_ref **mopp)
{
struct gnttab_map_grant_ref *mop = *mopp;
int pending_idx = *((u16 *)skb->data);
@@ -905,7 +918,7 @@ static int netbk_tx_check_mop(struct sk_buff *skb,
netif_put(netif);
} else {
set_phys_to_machine(
- __pa(idx_to_kaddr(pending_idx)) >> PAGE_SHIFT,
+ __pa(idx_to_kaddr(netbk, pending_idx)) >> PAGE_SHIFT,
FOREIGN_FRAME(mop->dev_bus_addr >> PAGE_SHIFT));
netbk->grant_tx_handle[pending_idx] = mop->handle;
}
@@ -923,14 +936,14 @@ static int netbk_tx_check_mop(struct sk_buff *skb,
newerr = (++mop)->status;
if (likely(!newerr)) {
unsigned long addr;
- addr = idx_to_kaddr(pending_idx);
+ addr = idx_to_kaddr(netbk, pending_idx);
set_phys_to_machine(
__pa(addr)>>PAGE_SHIFT,
FOREIGN_FRAME(mop->dev_bus_addr>>PAGE_SHIFT));
netbk->grant_tx_handle[pending_idx] = mop->handle;
/* Had a previous error? Invalidate this fragment. */
if (unlikely(err))
- netif_idx_release(pending_idx);
+ netif_idx_release(netbk, pending_idx);
continue;
}
@@ -947,10 +960,10 @@ static int netbk_tx_check_mop(struct sk_buff *skb,
/* First error: invalidate header and preceding fragments. */
pending_idx = *((u16 *)skb->data);
- netif_idx_release(pending_idx);
+ netif_idx_release(netbk, pending_idx);
for (j = start; j < i; j++) {
pending_idx = (unsigned long)shinfo->frags[i].page;
- netif_idx_release(pending_idx);
+ netif_idx_release(netbk, pending_idx);
}
/* Remember the error: invalidate all subsequent fragments. */
@@ -961,7 +974,7 @@ static int netbk_tx_check_mop(struct sk_buff *skb,
return err;
}
-static void netbk_fill_frags(struct sk_buff *skb)
+static void netbk_fill_frags(struct xen_netbk *netbk, struct sk_buff *skb)
{
struct skb_shared_info *shinfo = skb_shinfo(skb);
int nr_frags = shinfo->nr_frags;
@@ -979,7 +992,7 @@ static void netbk_fill_frags(struct sk_buff *skb)
&netbk->pending_inuse_head);
txp = &netbk->pending_tx_info[pending_idx].req;
- frag->page = virt_to_page(idx_to_kaddr(pending_idx));
+ frag->page = virt_to_page(idx_to_kaddr(netbk, pending_idx));
frag->size = txp->size;
frag->page_offset = txp->offset;
@@ -1111,14 +1124,15 @@ static bool tx_credit_exceeded(struct xen_netif *netif, unsigned size)
return false;
}
-static unsigned net_tx_build_mops(void)
+static unsigned net_tx_build_mops(struct xen_netbk *netbk)
{
struct gnttab_map_grant_ref *mop;
struct sk_buff *skb;
int ret;
+ int group;
mop = netbk->tx_map_ops;
- while (((nr_pending_reqs() + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
+ while (((nr_pending_reqs(netbk) + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
!list_empty(&netbk->net_schedule_list)) {
struct xen_netif *netif;
struct xen_netif_tx_request txreq;
@@ -1220,16 +1234,17 @@ static unsigned net_tx_build_mops(void)
}
}
- gnttab_set_map_op(mop, idx_to_kaddr(pending_idx),
+ gnttab_set_map_op(mop, idx_to_kaddr(netbk, pending_idx),
GNTMAP_host_map | GNTMAP_readonly,
txreq.gref, netif->domid);
mop++;
+ group = netif->group;
start_tracking_page(foreign_page_tracker,
netbk->mmap_pages[pending_idx],
netif->domid,
txreq.gref,
- pending_idx,
+ group * MAX_PENDING_REQS + pending_idx,
NULL);
memcpy(&netbk->pending_tx_info[pending_idx].req,
@@ -1253,7 +1268,7 @@ static unsigned net_tx_build_mops(void)
netbk->pending_cons++;
- mop = netbk_get_requests(netif, skb, txfrags, mop);
+ mop = netbk_get_requests(netbk, netif, skb, txfrags, mop);
netif->tx.req_cons = idx;
netif_schedule_work(netif);
@@ -1265,7 +1280,7 @@ static unsigned net_tx_build_mops(void)
return mop - netbk->tx_map_ops;
}
-static void net_tx_submit(void)
+static void net_tx_submit(struct xen_netbk *netbk)
{
struct gnttab_map_grant_ref *mop;
struct sk_buff *skb;
@@ -1282,7 +1297,7 @@ static void net_tx_submit(void)
txp = &netbk->pending_tx_info[pending_idx].req;
/* Check the remap error code. */
- if (unlikely(netbk_tx_check_mop(skb, &mop))) {
+ if (unlikely(netbk_tx_check_mop(netbk, skb, &mop))) {
DPRINTK("netback grant failed.\n");
skb_shinfo(skb)->nr_frags = 0;
kfree_skb(skb);
@@ -1291,7 +1306,7 @@ static void net_tx_submit(void)
data_len = skb->len;
memcpy(skb->data,
- (void *)(idx_to_kaddr(pending_idx)|txp->offset),
+ (void *)(idx_to_kaddr(netbk, pending_idx)|txp->offset),
data_len);
if (data_len < txp->size) {
/* Append the packet payload as a fragment. */
@@ -1299,7 +1314,7 @@ static void net_tx_submit(void)
txp->size -= data_len;
} else {
/* Schedule a response immediately. */
- netif_idx_release(pending_idx);
+ netif_idx_release(netbk, pending_idx);
}
/*
@@ -1311,7 +1326,7 @@ static void net_tx_submit(void)
else
skb->ip_summed = CHECKSUM_NONE;
- netbk_fill_frags(skb);
+ netbk_fill_frags(netbk, skb);
/*
* If the initial fragment was < PKT_PROT_LEN then
@@ -1360,15 +1375,16 @@ static void net_tx_submit(void)
}
/* Called after netfront has transmitted */
-static void net_tx_action(unsigned long unused)
+static void net_tx_action(unsigned long data)
{
+ struct xen_netbk *netbk = (struct xen_netbk *)data;
unsigned nr_mops;
int ret;
if (netbk->dealloc_cons != netbk->dealloc_prod)
- net_tx_action_dealloc();
+ net_tx_action_dealloc(netbk);
- nr_mops = net_tx_build_mops();
+ nr_mops = net_tx_build_mops(netbk);
if (nr_mops == 0)
return;
@@ -1377,10 +1393,10 @@ static void net_tx_action(unsigned long unused)
netbk->tx_map_ops, nr_mops);
BUG_ON(ret);
- net_tx_submit();
+ net_tx_submit(netbk);
}
-static void netif_idx_release(u16 pending_idx)
+static void netif_idx_release(struct xen_netbk *netbk, u16 pending_idx)
{
static DEFINE_SPINLOCK(_lock);
unsigned long flags;
@@ -1399,19 +1415,22 @@ static void netif_idx_release(u16 pending_idx)
static void netif_page_release(struct page *page, unsigned int order)
{
+ int group = ((struct page_ext *)(page->mapping))->group;
int idx = ((struct page_ext *)(page->mapping))->idx;
+ struct xen_netbk *netbk = &xen_netbk[group];
BUG_ON(order ||
idx < 0 || idx >= MAX_PENDING_REQS ||
netbk->mmap_pages[idx] != page);
- netif_idx_release(idx);
+ netif_idx_release(netbk, idx);
}
irqreturn_t netif_be_int(int irq, void *dev_id)
{
struct xen_netif *netif = dev_id;
+ struct xen_netbk *netbk = &xen_netbk[netif->group];
add_to_net_schedule_list_tail(netif);
- maybe_schedule_tx_action();
+ maybe_schedule_tx_action(netbk);
if (netif_schedulable(netif) && !netbk_queue_full(netif))
netif_wake_queue(netif->dev);
@@ -1477,7 +1496,8 @@ static struct xen_netif_rx_response *make_rx_response(struct xen_netif *netif,
static irqreturn_t netif_be_dbg(int irq, void *dev_id, struct pt_regs *regs)
{
struct list_head *ent;
- struct xen_netif *netif;
+ struct xen_netif *netif = dev_id;
+ struct xen_netbk *netbk = &xen_netbk[netif->group];
int i = 0;
printk(KERN_ALERT "netif_schedule_list:\n");
@@ -1512,66 +1532,81 @@ static int __init netback_init(void)
int i;
struct page *page;
int rc = 0;
+ int group = 0;
if (!xen_domain())
return -ENODEV;
- netbk = kzalloc(sizeof(struct xen_netbk), GFP_KERNEL);
- if (!netbk) {
+ xen_netbk_group_nr = num_online_cpus();
+ xen_netbk = kzalloc(xen_netbk_group_nr * sizeof(struct xen_netbk),
+ GFP_KERNEL);
+ if (!xen_netbk) {
printk(KERN_ALERT "%s: out of memory\n", __func__);
return -ENOMEM;
}
foreign_page_tracker =
- alloc_page_foreign_tracker(MAX_PENDING_REQS);
+ alloc_page_foreign_tracker(xen_netbk_group_nr *
+ MAX_PENDING_REQS);
if (!foreign_page_tracker) {
rc = -ENOMEM;
- goto failed_init3;
+ goto failed_init2;
}
/* We can increase reservation by this much in net_rx_action(). */
// balloon_update_driver_allowance(NET_RX_RING_SIZE);
- skb_queue_head_init(&netbk->rx_queue);
- skb_queue_head_init(&netbk->tx_queue);
-
- init_timer(&netbk->net_timer);
- netbk->net_timer.data = 0;
- netbk->net_timer.function = net_alarm;
-
- init_timer(&netbk->netbk_tx_pending_timer);
- netbk->netbk_tx_pending_timer.data = 0;
- netbk->netbk_tx_pending_timer.function = netbk_tx_pending_timeout;
+ for (group = 0; group < xen_netbk_group_nr; group++) {
+ struct xen_netbk *netbk = &xen_netbk[group];
+ skb_queue_head_init(&netbk->rx_queue);
+ skb_queue_head_init(&netbk->tx_queue);
+
+ init_timer(&netbk->net_timer);
+ netbk->net_timer.data = (unsigned long)netbk;
+ netbk->net_timer.function = net_alarm;
+
+ init_timer(&netbk->netbk_tx_pending_timer);
+ netbk->netbk_tx_pending_timer.data = (unsigned long)netbk;
+ netbk->netbk_tx_pending_timer.function =
+ netbk_tx_pending_timeout;
+
+ netbk->mmap_pages =
+ alloc_empty_pages_and_pagevec(MAX_PENDING_REQS);
+ if (!netbk->mmap_pages) {
+ printk(KERN_ALERT "%s: out of memory\n", __func__);
+ del_timer(&netbk->netbk_tx_pending_timer);
+ del_timer(&netbk->net_timer);
+ rc = -ENOMEM;
+ goto failed_init1;
+ }
- netbk->mmap_pages =
- alloc_empty_pages_and_pagevec(MAX_PENDING_REQS);
- if (!netbk->mmap_pages) {
- printk(KERN_ALERT "%s: out of memory\n", __func__);
- rc = -ENOMEM;
- goto failed_init2;
- }
+ for (i = 0; i < MAX_PENDING_REQS; i++) {
+ page = netbk->mmap_pages[i];
+ SetPageForeign(page, netif_page_release);
+ netbk->page_extinfo[i].group = group;
+ netbk->page_extinfo[i].idx = i;
+ netif_set_page_index(page, &netbk->page_extinfo[i]);
+ INIT_LIST_HEAD(&netbk->pending_inuse[i].list);
+ }
- for (i = 0; i < MAX_PENDING_REQS; i++) {
- page = netbk->mmap_pages[i];
- SetPageForeign(page, netif_page_release);
- netbk->page_extinfo[i].group = 0;
- netbk->page_extinfo[i].idx = i;
- netif_set_page_index(page, &netbk->page_extinfo[i]);
- INIT_LIST_HEAD(&netbk->pending_inuse[i].list);
- }
+ netbk->pending_cons = 0;
+ netbk->pending_prod = MAX_PENDING_REQS;
+ for (i = 0; i < MAX_PENDING_REQS; i++)
+ netbk->pending_ring[i] = i;
- netbk->pending_cons = 0;
- netbk->pending_prod = MAX_PENDING_REQS;
- for (i = 0; i < MAX_PENDING_REQS; i++)
- netbk->pending_ring[i] = i;
+ tasklet_init(&netbk->net_tx_tasklet, net_tx_action,
+ (unsigned long)netbk);
+ tasklet_init(&netbk->net_rx_tasklet, net_rx_action,
+ (unsigned long)netbk);
- tasklet_init(&netbk->net_tx_tasklet, net_tx_action, 0);
- tasklet_init(&netbk->net_rx_tasklet, net_rx_action, 0);
+ INIT_LIST_HEAD(&netbk->pending_inuse_head);
+ INIT_LIST_HEAD(&netbk->net_schedule_list);
- INIT_LIST_HEAD(&netbk->pending_inuse_head);
- INIT_LIST_HEAD(&netbk->net_schedule_list);
+ spin_lock_init(&netbk->net_schedule_list_lock);
- spin_lock_init(&netbk->net_schedule_list_lock);
+ spin_lock_init(&netbk->group_operation_lock);
+ netbk->netfront_count = 0;
+ }
netbk_copy_skb_mode = NETBK_DONT_COPY_SKB;
if (MODPARM_copy_skb) {
@@ -1600,13 +1635,16 @@ static int __init netback_init(void)
return 0;
failed_init1:
- free_empty_pages_and_pagevec(netbk->mmap_pages, MAX_PENDING_REQS);
-failed_init2:
+ for (i = 0; i < group; i++) {
+ struct xen_netbk *netbk = &xen_netbk[i];
+ free_empty_pages_and_pagevec(netbk->mmap_pages,
+ MAX_PENDING_REQS);
+ del_timer(&netbk->netbk_tx_pending_timer);
+ del_timer(&netbk->net_timer);
+ }
free_page_foreign_tracker(foreign_page_tracker);
- del_timer(&netbk->netbk_tx_pending_timer);
- del_timer(&netbk->net_timer);
-failed_init3:
- kfree(netbk);
+failed_init2:
+ kfree(xen_netbk);
return rc;
}
--
1.6.0
[-- Attachment #3: Type: text/plain, Size: 138 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [Pv-ops][PATCH 3/4 v2] Netback: Multiple tasklets support
2010-04-29 14:28 [Pv-ops][PATCH 3/4 v2] Netback: Multiple tasklets support Xu, Dongxiao
@ 2010-05-03 16:06 ` Konrad Rzeszutek Wilk
2010-05-04 0:55 ` Xu, Dongxiao
0 siblings, 1 reply; 4+ messages in thread
From: Konrad Rzeszutek Wilk @ 2010-05-03 16:06 UTC (permalink / raw)
To: Xu, Dongxiao
Cc: Jeremy Fitzhardinge, xen-devel@lists.xensource.com, Steven Smith
On Thu, Apr 29, 2010 at 10:28:50PM +0800, Xu, Dongxiao wrote:
> Netback: Multiple tasklets support.
>
> Now netback uses one pair of tasklets for Tx/Rx data transaction.
> Netback tasklet could only run at one CPU at a time, and it is
> used to serve all the netfronts. Therefore it has become a
> performance bottle neck. This patch is to use multiple tasklet
> pairs to replace the current single pair in dom0.
>
> Assuming that Dom0 has CPUNR VCPUs, we define CPUNR kinds of
> tasklets pair (CPUNR for Tx, and CPUNR for Rx). Each pare of
^^^ -> pair
> tasklets serve specific group of netfronts. Also for those global
> and static variables, we duplicated them for each group in
> order to avoid the spinlock.
scripts/checkpatch.pl --strict
~/0003-Netback-Multiple-tasklets-support.patch
CHECK: spinlock_t definition without comment
#42: FILE: drivers/xen/netback/common.h:292:
+ spinlock_t group_operation_lock;
total: 0 errors, 0 warnings, 1 checks, 626 lines checked
/home/konrad/0003-Netback-Multiple-tasklets-support.patch has style
problems, please review. If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
>
> Signed-off-by: Dongxiao Xu <dongxiao.xu@intel.com>
+static void netbk_add_netif(struct xen_netbk *netbk, int group_nr,
+ struct xen_netif *netif)
+{
+ int i;
+ int min_netfront_count;
+ int min_group = 0;
+ spin_lock(&netbk->group_operation_lock);
+ min_netfront_count = netbk[0].netfront_count;
+ for (i = 0; i < group_nr; i++) {
+ if (netbk[i].netfront_count < min_netfront_count) {
+ min_group = i;
+ min_netfront_count = netbk[i].netfront_count;
Should you have a 'break' here? I am not sure if it makes sense to go
through all of the tasklets to set the min_group and min_netfrount_count to the last
one?
+ }
+ }
+
+ netif->group = min_group;
+ netbk[netif->group].netfront_count++;
+ spin_unlock(&netbk->group_operation_lock);
+}
+
+static void netbk_remove_netif(struct xen_netbk *netbk, struct xen_netif *netif)
+{
+ spin_lock(&netbk->group_operation_lock);
+ netbk[netif->group].netfront_count--;
+ spin_unlock(&netbk->group_operation_lock);
+}
+
static void __netif_up(struct xen_netif *netif)
{
enable_irq(netif->irq);
@@ -333,6 +360,8 @@ int netif_map(struct xen_netif *netif, unsigned long tx_ring_ref,
if (netif->rx_comms_area == NULL)
goto err_rx;
+ netbk_add_netif(xen_netbk, xen_netbk_group_nr, netif);
+
Say you have 7 VIFs and only 4 VCPUs, are these netfront_count values
correct?
netbk[0].netfront_count == 1; /* vif0 added */
netbk[3].netfront_count == 1; /* vif1 added */
netbk[2].netfront_count == 1; /* vif2 added */
netbk[1].netfront_count == 1; /* vif3 added */
netbk[0].netfront_count == 2; /* vif4 added */
netbk[3].netfront_count == 2; /* vif5 added */
netbk[2].netfront_count == 2; /* vif6 added */
I just want to make sure I understand the allocation algorithm
correctly.
^ permalink raw reply [flat|nested] 4+ messages in thread
* RE: [Pv-ops][PATCH 3/4 v2] Netback: Multiple tasklets support
2010-05-03 16:06 ` Konrad Rzeszutek Wilk
@ 2010-05-04 0:55 ` Xu, Dongxiao
2010-05-04 13:23 ` Konrad Rzeszutek Wilk
0 siblings, 1 reply; 4+ messages in thread
From: Xu, Dongxiao @ 2010-05-04 0:55 UTC (permalink / raw)
To: Konrad Rzeszutek Wilk
Cc: Fitzhardinge, xen-devel@lists.xensource.com, Jeremy, Steven Smith
Konrad Rzeszutek Wilk wrote:
> On Thu, Apr 29, 2010 at 10:28:50PM +0800, Xu, Dongxiao wrote:
>> Netback: Multiple tasklets support.
>>
>> Now netback uses one pair of tasklets for Tx/Rx data transaction.
>> Netback tasklet could only run at one CPU at a time, and it is
>> used to serve all the netfronts. Therefore it has become a
>> performance bottle neck. This patch is to use multiple tasklet
>> pairs to replace the current single pair in dom0.
>>
>> Assuming that Dom0 has CPUNR VCPUs, we define CPUNR kinds of
>> tasklets pair (CPUNR for Tx, and CPUNR for Rx). Each pare of
>> ^^^ -> pair
>
>> tasklets serve specific group of netfronts. Also for those global
>> and static variables, we duplicated them for each group in
>> order to avoid the spinlock.
>
> scripts/checkpatch.pl --strict
> ~/0003-Netback-Multiple-tasklets-support.patch
> CHECK: spinlock_t definition without comment
> #42: FILE: drivers/xen/netback/common.h:292:
> + spinlock_t group_operation_lock;
>
> total: 0 errors, 0 warnings, 1 checks, 626 lines checked
>
> /home/konrad/0003-Netback-Multiple-tasklets-support.patch has style
> problems, please review. If any of these errors
> are false positives report them to the maintainer, see
> CHECKPATCH in MAINTAINERS.
Thanks, I will modify it in next version.
>
>
>>
>> Signed-off-by: Dongxiao Xu <dongxiao.xu@intel.com>
>
> +static void netbk_add_netif(struct xen_netbk *netbk, int group_nr,
> + struct xen_netif *netif)
> +{
> + int i;
> + int min_netfront_count;
> + int min_group = 0;
> + spin_lock(&netbk->group_operation_lock);
> + min_netfront_count = netbk[0].netfront_count;
> + for (i = 0; i < group_nr; i++) {
> + if (netbk[i].netfront_count < min_netfront_count) {
> + min_group = i;
> + min_netfront_count = netbk[i].netfront_count;
>
> Should you have a 'break' here? I am not sure if it makes sense to go
> through all of the tasklets to set the min_group and
> min_netfrount_count to the last one?
To find the minimum count, I think it should go through all the tasklsets.
>
> + }
> + }
> +
> + netif->group = min_group;
> + netbk[netif->group].netfront_count++;
> + spin_unlock(&netbk->group_operation_lock);
> +}
> +
> +static void netbk_remove_netif(struct xen_netbk *netbk, struct
> xen_netif *netif) +{
> + spin_lock(&netbk->group_operation_lock);
> + netbk[netif->group].netfront_count--;
> + spin_unlock(&netbk->group_operation_lock);
> +}
> +
> static void __netif_up(struct xen_netif *netif)
> {
> enable_irq(netif->irq);
> @@ -333,6 +360,8 @@ int netif_map(struct xen_netif *netif, unsigned
> long tx_ring_ref, if (netif->rx_comms_area == NULL)
> goto err_rx;
>
> + netbk_add_netif(xen_netbk, xen_netbk_group_nr, netif);
> +
>
> Say you have 7 VIFs and only 4 VCPUs, are these netfront_count values
> correct?
>
> netbk[0].netfront_count == 1; /* vif0 added */
> netbk[3].netfront_count == 1; /* vif1 added */
> netbk[2].netfront_count == 1; /* vif2 added */
> netbk[1].netfront_count == 1; /* vif3 added */
> netbk[0].netfront_count == 2; /* vif4 added */
> netbk[3].netfront_count == 2; /* vif5 added */
> netbk[2].netfront_count == 2; /* vif6 added */
Basically it is true, but the order may be changed.
netbk[0].netfront_count == 1; /* vif0 added */
netbk[1].netfront_count == 1; /* vif1 added */
netbk[2].netfront_count == 1; /* vif2 added */
netbk[3].netfront_count == 1; /* vif3 added */
netbk[0].netfront_count == 2; /* vif4 added */
netbk[1].netfront_count == 2; /* vif5 added */
netbk[2].netfront_count == 2; /* vif6 added */
>
> I just want to make sure I understand the allocation algorithm
> correctly.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [Pv-ops][PATCH 3/4 v2] Netback: Multiple tasklets support
2010-05-04 0:55 ` Xu, Dongxiao
@ 2010-05-04 13:23 ` Konrad Rzeszutek Wilk
0 siblings, 0 replies; 4+ messages in thread
From: Konrad Rzeszutek Wilk @ 2010-05-04 13:23 UTC (permalink / raw)
To: Xu, Dongxiao
Cc: Jeremy Fitzhardinge, xen-devel@lists.xensource.com, Steven Smith
> > +static void netbk_add_netif(struct xen_netbk *netbk, int group_nr,
> > + struct xen_netif *netif)
> > +{
> > + int i;
> > + int min_netfront_count;
> > + int min_group = 0;
> > + spin_lock(&netbk->group_operation_lock);
> > + min_netfront_count = netbk[0].netfront_count;
> > + for (i = 0; i < group_nr; i++) {
> > + if (netbk[i].netfront_count < min_netfront_count) {
> > + min_group = i;
> > + min_netfront_count = netbk[i].netfront_count;
> >
> > Should you have a 'break' here? I am not sure if it makes sense to go
> > through all of the tasklets to set the min_group and
> > min_netfrount_count to the last one?
>
> To find the minimum count, I think it should go through all the tasklsets.
Ahh yes (duh!). I missed the 'min_netfrount_count' assigment! That makes much
more sense.
.. snip ..
> > Say you have 7 VIFs and only 4 VCPUs, are these netfront_count values
> > correct?
> >
> > netbk[0].netfront_count == 1; /* vif0 added */
> > netbk[3].netfront_count == 1; /* vif1 added */
> > netbk[2].netfront_count == 1; /* vif2 added */
> > netbk[1].netfront_count == 1; /* vif3 added */
> > netbk[0].netfront_count == 2; /* vif4 added */
> > netbk[3].netfront_count == 2; /* vif5 added */
> > netbk[2].netfront_count == 2; /* vif6 added */
>
> Basically it is true, but the order may be changed.
<nods>
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2010-05-04 13:23 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-04-29 14:28 [Pv-ops][PATCH 3/4 v2] Netback: Multiple tasklets support Xu, Dongxiao
2010-05-03 16:06 ` Konrad Rzeszutek Wilk
2010-05-04 0:55 ` Xu, Dongxiao
2010-05-04 13:23 ` Konrad Rzeszutek Wilk
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).