usbnet: optimize usbnet_bh() to reduce CPU load
The current source pushes skb into dev-done queue by calling skb_dequeue_tail() and then pop it by skb_dequeue() to branch to rx_cleanup state for freeing urb/skb in usbnet_bh(). It takes extra CPU load, 2.21% (skb_queue_tail) as follows, - 11.58% 0.26% swapper [k] usbnet_bh - 11.32% usbnet_bh - 6.43% skb_dequeue 6.34% _raw_spin_unlock_irqrestore - 2.21% skb_queue_tail 2.19% _raw_spin_unlock_irqrestore - 1.68% consume_skb - 0.97% kfree_skbmem 0.80% kmem_cache_free 0.53% skb_release_data To reduce the extra CPU load use return values to call helper function usb_free_skb() to free the resources instead of calling skb_queue_tail() and skb_dequeue() for push and pop respectively. - 7.87% 0.25% swapper [k] usbnet_bh - 7.62% usbnet_bh - 4.81% skb_dequeue 4.74% _raw_spin_unlock_irqrestore - 1.75% consume_skb - 0.98% kfree_skbmem 0.78% kmem_cache_free 0.58% skb_release_data 0.53% smsc95xx_rx_fixup Signed-off-by: Leesoo Ahn <lsahn@ooseel.net> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
9cb8bae3d1
commit
fb59bf28cd
|
@ -555,32 +555,30 @@ static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags)
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static inline void rx_process (struct usbnet *dev, struct sk_buff *skb)
|
||||
static inline int rx_process(struct usbnet *dev, struct sk_buff *skb)
|
||||
{
|
||||
if (dev->driver_info->rx_fixup &&
|
||||
!dev->driver_info->rx_fixup (dev, skb)) {
|
||||
/* With RX_ASSEMBLE, rx_fixup() must update counters */
|
||||
if (!(dev->driver_info->flags & FLAG_RX_ASSEMBLE))
|
||||
dev->net->stats.rx_errors++;
|
||||
goto done;
|
||||
return -EPROTO;
|
||||
}
|
||||
// else network stack removes extra byte if we forced a short packet
|
||||
|
||||
/* all data was already cloned from skb inside the driver */
|
||||
if (dev->driver_info->flags & FLAG_MULTI_PACKET)
|
||||
goto done;
|
||||
return -EALREADY;
|
||||
|
||||
if (skb->len < ETH_HLEN) {
|
||||
dev->net->stats.rx_errors++;
|
||||
dev->net->stats.rx_length_errors++;
|
||||
netif_dbg(dev, rx_err, dev->net, "rx length %d\n", skb->len);
|
||||
} else {
|
||||
usbnet_skb_return(dev, skb);
|
||||
return;
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
done:
|
||||
skb_queue_tail(&dev->done, skb);
|
||||
usbnet_skb_return(dev, skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
@ -1514,6 +1512,14 @@ err:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static inline void usb_free_skb(struct sk_buff *skb)
|
||||
{
|
||||
struct skb_data *entry = (struct skb_data *)skb->cb;
|
||||
|
||||
usb_free_urb(entry->urb);
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
// tasklet (work deferred from completions, in_irq) or timer
|
||||
|
@ -1528,15 +1534,14 @@ static void usbnet_bh (struct timer_list *t)
|
|||
entry = (struct skb_data *) skb->cb;
|
||||
switch (entry->state) {
|
||||
case rx_done:
|
||||
entry->state = rx_cleanup;
|
||||
rx_process (dev, skb);
|
||||
if (rx_process(dev, skb))
|
||||
usb_free_skb(skb);
|
||||
continue;
|
||||
case tx_done:
|
||||
kfree(entry->urb->sg);
|
||||
fallthrough;
|
||||
case rx_cleanup:
|
||||
usb_free_urb (entry->urb);
|
||||
dev_kfree_skb (skb);
|
||||
usb_free_skb(skb);
|
||||
continue;
|
||||
default:
|
||||
netdev_dbg(dev->net, "bogus skb state %d\n", entry->state);
|
||||
|
|
Loading…
Reference in New Issue