From patchwork Tue Nov 4 05:37:58 2008 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: stephen hemminger X-Patchwork-Id: 7047 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by ozlabs.org (Postfix) with ESMTP id 2BF10DDE9E for ; Tue, 4 Nov 2008 16:38:07 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751435AbYKDFiB (ORCPT ); Tue, 4 Nov 2008 00:38:01 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1751353AbYKDFiA (ORCPT ); Tue, 4 Nov 2008 00:38:00 -0500 Received: from mail.vyatta.com ([76.74.103.46]:33681 "EHLO mail.vyatta.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751224AbYKDFiA (ORCPT ); Tue, 4 Nov 2008 00:38:00 -0500 Received: from localhost (localhost.localdomain [127.0.0.1]) by mail.vyatta.com (Postfix) with ESMTP id 2242F4F4219; Mon, 3 Nov 2008 21:38:01 -0800 (PST) X-Virus-Scanned: amavisd-new at Received: from mail.vyatta.com ([127.0.0.1]) by localhost (mail.vyatta.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id zpxguG9e6rVS; Mon, 3 Nov 2008 21:38:00 -0800 (PST) Received: from extreme (unknown [96.225.231.79]) by mail.vyatta.com (Postfix) with ESMTP id 73A354F420D; Mon, 3 Nov 2008 21:38:00 -0800 (PST) Date: Mon, 3 Nov 2008 21:37:58 -0800 From: Stephen Hemminger To: David Miller Cc: netdev@vger.kernel.org Subject: [RFC] loopback: optimization Message-ID: <20081103213758.59a8361d@extreme> Organization: Vyatta X-Mailer: Claws Mail 3.3.1 (GTK+ 2.12.9; x86_64-pc-linux-gnu) Mime-Version: 1.0 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org This is something I was trying out to try improving loopback performance. It moves loopback processing from the generic backlog per-cpu queues, to its own set of queues. I thought this might help the cache locality and the loopback doesn't have to do relatively expensive local_irq_disable() operations. BUT it didn't seem to help with tbench, but it might help others who want to go farther with it. Code runs but treat it ASIS at this point. Signed-off-by: Stephen Hemminger the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html --- a/drivers/net/loopback.c 2008-11-03 10:13:31.000000000 -0800 +++ b/drivers/net/loopback.c 2008-11-03 11:05:52.000000000 -0800 @@ -59,51 +59,79 @@ #include #include -struct pcpu_lstats { +struct loopback_per_cpu { + struct sk_buff_head rxq; + struct napi_struct napi; + unsigned long packets; unsigned long bytes; }; + /* * The higher levels take care of making this non-reentrant (it's * called with bh's disabled). */ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) { - struct pcpu_lstats *pcpu_lstats, *lb_stats; + struct loopback_per_cpu *lo = dev->ml_priv, *pcpu; skb_orphan(skb); - skb->protocol = eth_type_trans(skb,dev); + skb->protocol = eth_type_trans(skb, dev); dev->last_rx = jiffies; /* it's OK to use per_cpu_ptr() because BHs are off */ - pcpu_lstats = dev->ml_priv; - lb_stats = per_cpu_ptr(pcpu_lstats, smp_processor_id()); - lb_stats->bytes += skb->len; - lb_stats->packets++; + pcpu = per_cpu_ptr(lo, smp_processor_id()); - netif_rx(skb); + if (likely(pcpu->rxq.qlen < netdev_max_backlog)) { + if (pcpu->rxq.qlen == 0) + __napi_schedule(&lo->napi); + + __skb_queue_tail(&pcpu->rxq, skb); + pcpu->bytes += skb->len; + pcpu->packets++; + + return NET_XMIT_SUCCESS; + } else { + dev->stats.rx_dropped++; + dev_kfree_skb_any(skb); + return NET_XMIT_DROP; + } +} - return 0; +static int loopback_poll(struct napi_struct *napi, int work_limit) +{ + struct loopback_per_cpu *pcpu + = container_of(napi, struct loopback_per_cpu, napi); + struct sk_buff *skb; + int work_done = 0; + + while ( (skb = __skb_dequeue(&pcpu->rxq)) ) { + netif_receive_skb(skb); + + if (++work_done >= work_limit) + goto done; + } + + __napi_complete(napi); +done: + return work_done; } static struct net_device_stats *get_stats(struct net_device *dev) { - const struct pcpu_lstats *pcpu_lstats; + const struct loopback_per_cpu *lo = dev->ml_priv; struct net_device_stats *stats = &dev->stats; unsigned long bytes = 0; unsigned long packets = 0; int i; - pcpu_lstats = dev->ml_priv; for_each_possible_cpu(i) { - const struct pcpu_lstats *lb_stats; - - lb_stats = per_cpu_ptr(pcpu_lstats, i); - bytes += lb_stats->bytes; - packets += lb_stats->packets; + const struct loopback_per_cpu *pcpu = per_cpu_ptr(lo, i); + bytes += pcpu->bytes; + packets += pcpu->packets; } stats->rx_packets = packets; stats->tx_packets = packets; @@ -127,21 +155,43 @@ static const struct ethtool_ops loopback static int loopback_dev_init(struct net_device *dev) { - struct pcpu_lstats *lstats; + struct loopback_per_cpu *lo; + int i; - lstats = alloc_percpu(struct pcpu_lstats); - if (!lstats) + lo = alloc_percpu(struct loopback_per_cpu); + if (!lo) return -ENOMEM; - dev->ml_priv = lstats; + dev->ml_priv = lo; + + for_each_possible_cpu(i) { + struct loopback_per_cpu *pcpu = per_cpu_ptr(lo, i); + skb_queue_head_init(&pcpu->rxq); + netif_napi_add(dev, &pcpu->napi, loopback_poll, 64); + } + + return 0; +} + +static int loopback_dev_stop(struct net_device *dev) +{ + struct loopback_per_cpu *lo = dev->ml_priv; + int i; + + for_each_possible_cpu(i) { + struct loopback_per_cpu *pcpu = per_cpu_ptr(lo, i); + + napi_synchronize(&pcpu->napi); + __skb_queue_purge(&pcpu->rxq); + } return 0; } static void loopback_dev_free(struct net_device *dev) { - struct pcpu_lstats *lstats = dev->ml_priv; + struct loopback_per_cpu *lo = dev->ml_priv; - free_percpu(lstats); + free_percpu(lo); free_netdev(dev); } @@ -169,6 +219,7 @@ static void loopback_setup(struct net_de dev->header_ops = ð_header_ops; dev->init = loopback_dev_init; dev->destructor = loopback_dev_free; + dev->stop = loopback_dev_stop; } -- To unsubscribe from this list: send the line "unsubscribe netdev" in