net: low latency Ethernet device polling
Subsystems (8)
v7 cover net: low latency Ethernet device polling
more fixes.
Thank you all for your input.
-Eliezer
change log:
v7
- suggested by Ben Hutchings and Eric Dumazet:
type fixes, static for globals in net/core.c,
avoid napi_id collisions in napi_hash_add()
v6
- many small fixes suggested by Eric Dumazet:
data locality, typos, documentation
protect napi_hash insert/delete with a spinlock (napi_gen_id is no longer atomic_t since it's only accessed with the spinlock held.)
- added IPv6 TCP and UDP support (only minimally tested)
v5
- corrections suggested by Ben Hutchings:
fixed typos, moved the config option and sysctl value from IPv4 to net
- moved sk_mark_ll() to the protocol handlers
- removed global id mechanism, replaced with a hashed napi_id. based on code sample from Eric Dumazet
Note that ixgbe_free_q_vector() already waits an rcu grace period before freeing the q_vector, so nothing additional needs to be done when adding a call to napi_hash_del().
- simple poll/select support
v4
- removed separate config option for TCP as suggested Eric Dumazet.
- added linux mib counter for packets received through the low latency path, as suggested by Andi Kleen.
- re-allow module unloading, remove module param, use a global generation id instead to prevent the use of a stale napi pointer, as suggested by Eric Dumazet
- updated Documentation/networking/ip-sysctl.txt text
v3
- coding style changes suggested by Dave Miller
v2
- the sysctl knob is now in microseconds. The default value is now 0 (off).
- for now the code depends at configure time on CONFIG_I86_TSC
- the napi reference in struct skb is now a union with the dma cookie since the former is only used on RX and the latter on TX,
as suggested by Eric Dumazet.
- we do a better job at honoring non-blocking operations.
- removed busy-polling support for tcp_read_sock()
- remove dynamic disabling of GRO
- coding style fixes
- disallow unloading the device module after the feature has been used
Credit:
Jesse Brandeburg, Arun Chekhov Ilango, Julie Cummings, Alexander Duyck, Eric Geisler, Jason Neighbors, Yadong Li, Mike Polehn, Anil Vasudevan, Don Wood
Special thanks for finding bugs in earlier versions:
Willem de Bruijn and Andi Kleen
PATCH v7 1/5 net: add napi_id and hash
Adds a napi_id and a hashing mechanism to lookup a napi by id. This will be used by subsequent patches to implement low latency Ethernet device polling.
Based on a code sample by Eric Dumazet.
---
include/linux/netdevice.h | 29 ++++++++++++++++++++++ net/core/dev.c | 59 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 0 deletions(-)
include/linux/netdevice.h +29 -0
@@ -324,12 +324,15 @@ struct napi_struct {struct sk_buff *gro_list;struct sk_buff *skb;struct list_head dev_list; +struct hlist_node napi_hash_node; +unsigned int napi_id; };enum {NAPI_STATE_SCHED ,/* Poll is scheduled */ NAPI_STATE_DISABLE ,/* Disable pending */ NAPI_STATE_NPSVC ,/* Netpoll - don't dequeue from poll_list */ +NAPI_STATE_HASHED ,/* In NAPI hash */ };enum gro_result {
@@ -446,6 +449,32 @@ extern void __napi_complete(struct napi_struct *n);extern void napi_complete (struct napi_struct *n);/** +* napi_by_id - lookup a NAPI by napi_id +* @napi_id: hashed napi_id +* +* lookup @napi_id in napi_hash table +* must be called under rcu_read_lock() +*/ +extern struct napi_struct *napi_by_id (unsigned int napi_id); + +/** +* napi_hash_add - add a NAPI to global hashtable +* @napi: napi context +* +* generate a new napi_id and store a @napi under it in napi_hash +*/ +extern void napi_hash_add (struct napi_struct *napi); + +/** +* napi_hash_del - remove a NAPI from global table +* @napi: napi context +* +* Warning: caller must observe rcu grace period +* before freeing memory containing @napi +*/ +extern void napi_hash_del (struct napi_struct *napi); + +/** * napi_disable - prevent NAPI from scheduling * @n: napi context *
net/core/dev.c +59 -0
77 lines not on this page · raw message
------------------------------------------------------------------------------
Introducing AppDynamics Lite, a free troubleshooting tool for Java/.NET
Get 100% visibility into your production application - at no cost.
Code-level diagnostics for performance bottlenecks with <2% overhead
Download for free and get started troubleshooting in minutes.
http://p.sf.net/sfu/appdyn_d2d_ap1
_______________________________________________
E1000-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/e1000-devel
To learn more about Intel® Ethernet, visit http://communities.intel.com/community/wired
PATCH v7 2/5 net: implement support for low latency socket polling
In reply to Eliezer TamirAdds a new ndo_ll_poll method and the code that supports and uses it. This method can be used by low latency applications to busy poll Ethernet device queues directly from the socket code. The value of sysctl_net_ll_poll controls how many microseconds to poll. Set to zero to disable.
---
Documentation/sysctl/net.txt | 7 ++ fs/select.c | 7 ++ include/linux/netdevice.h | 3 + include/linux/skbuff.h | 8 ++ include/net/ll_poll.h | 148 ++++++++++++++++++++++++++++++++++++++++++ include/net/sock.h | 4 + include/uapi/linux/snmp.h | 1 net/Kconfig | 12 +++ net/core/datagram.c | 4 + net/core/skbuff.c | 4 + net/core/sock.c | 6 ++ net/core/sysctl_net_core.c | 10 +++ net/ipv4/proc.c | 1 net/ipv4/udp.c | 6 +- net/ipv6/udp.c | 6 +- net/socket.c | 16 ++++- 16 files changed, 238 insertions(+), 5 deletions(-) create mode 100644 include/net/ll_poll.h
Documentation/sysctl/net.txt +7 -0
@@ -50,6 +50,13 @@ The maximum number of packets that kernel can handle on a NAPI interrupt, it's a Per-CPU variable. Default: 64 +low_latency_poll +---------------- +Low latency busy poll timeout. (needs CONFIG_NET_LL_RX_POLL) +Approximate time in us to spin waiting for packets on the device queue. +Recommended value is 50. May increase power usage. +Default: 0 (off) + rmem_default ------------
fs/select.c +7 -0
@@ -27,6 +27,7 @@#include <linux/rcupdate.h> #include <linux/hrtimer.h> #include <linux/sched/rt.h> +#include <net/ll_poll.h> #include <asm/uaccess.h>
@@ -400,6 +401,7 @@ int do_select(int n, fd_set_bits *fds, struct timespec *end_time)poll_table *wait;int retval, i, timed_out =0 ;unsigned long slack =0 ; +cycles_t ll_time =ll_end_time ();rcu_read_lock (); retval =max_select_fd (n, fds);
@@ -486,6 +488,8 @@ int do_select(int n, fd_set_bits *fds, struct timespec *end_time)break ; } +if (can_poll_ll (ll_time)) +continue ;/* * If this is the first loop and we have a timeout * given, then we convert to ktime_t and set the to
@@ -750,6 +754,7 @@ static int do_poll(unsigned int nfds, struct poll_list *list,ktime_t expire, *to =NULL ;int timed_out =0 , count =0 ;unsigned long slack =0 ; +cycles_t ll_time =ll_end_time ();/* Optimise the no-wait case */ if (end_time && !end_time->tv_sec && !end_time->tv_nsec) {
@@ -795,6 +800,8 @@ static int do_poll(unsigned int nfds, struct poll_list *list,if (count || timed_out)break ; +if (can_poll_ll (ll_time)) +continue ;/* * If this is the first loop and we have a timeout * given, then we convert to ktime_t and set the to
include/linux/netdevice.h +3 -0
@@ -972,6 +972,9 @@ struct net_device_ops { gfp_t gfp);void (*ndo_netpoll_cleanup)(struct net_device *dev);#endif +#ifdef CONFIG_NET_LL_RX_POLL +int (*ndo_ll_poll)(struct napi_struct *dev); +#endif int (*ndo_set_vf_mac)(struct net_device *dev,int queue,u8 *mac); int (*ndo_set_vf_vlan)(struct net_device *dev,
include/linux/skbuff.h +6 -2
@@ -386,6 +386,7 @@ typedef unsigned char *sk_buff_data_t;* @no_fcs: Request NIC to treat last 4 bytes as Ethernet FCS * @dma_cookie: a cookie to one of several possible DMA operations * done by skb DMA functions +* @napi_id: id of the NAPI struct this skb came from * @secmark: security marking * @mark: Generic packet mark * @dropcount: total number of sk_receive_queue overflows
@@ -500,8 +501,11 @@ struct sk_buff {/* 7/9 bit hole (depending on ndisc_nodetype presence) */ kmemcheck_bitfield_end (flags2); -#ifdef CONFIG_NET_DMA -dma_cookie_t dma_cookie; +#if definedCONFIG_NET_DMA || definedCONFIG_NET_LL_RX_POLL +union { +unsigned int napi_id; +dma_cookie_t dma_cookie; + };#endif #ifdef CONFIG_NETWORK_SECMARK __u32 secmark;
include/net/ll_poll.h new file +148 -0
148 lines not on this page · raw message
include/net/sock.h +4 -0
@@ -229,6 +229,7 @@ struct cg_proto;* @sk_omem_alloc: "o" is "option" or "other" * @sk_wmem_queued: persistent queue size * @sk_forward_alloc: space allocated forward +* @sk_napi_id: id of the last napi context to receive data for sk * @sk_allocation: allocation mode * @sk_sndbuf: size of send buffer in bytes * @sk_flags: %SO_LINGER (l_onoff), %SO_BROADCAST, %SO_KEEPALIVE,
@@ -325,6 +326,9 @@ struct sock {#ifdef CONFIG_RPS __u32 sk_rxhash;#endif +#ifdef CONFIG_NET_LL_RX_POLL +unsigned int sk_napi_id; +#endif atomic_t sk_drops;int sk_rcvbuf;
include/uapi/linux/snmp.h +1 -0
@@ -253,6 +253,7 @@ enumLINUX_MIB_TCPFASTOPENLISTENOVERFLOW ,/* TCPFastOpenListenOverflow */ LINUX_MIB_TCPFASTOPENCOOKIEREQD ,/* TCPFastOpenCookieReqd */ LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES ,/* TCPSpuriousRtxHostQueues */ +LINUX_MIB_LOWLATENCYRXPACKETS ,/* LowLatencyRxPackets */ __LINUX_MIB_MAX };
net/Kconfig +12 -0
@@ -243,6 +243,18 @@ config NETPRIO_CGROUP Cgroup subsystem for use in assigning processes to network priorities on a per-interface basis +config NET_LL_RX_POLL + bool "Low Latency Receive Poll" + depends on X86_TSC + default n + ---help--- + Support Low Latency Receive Queue Poll. + (For network card drivers which support this option.) + When waiting for data in read or poll call directly into the the device driver + to flush packets which may be pending on the device queues into the stack. + + If unsure, say N. + config BQL boolean depends on SYSFS
net/core/datagram.c +4 -0
@@ -56,6 +56,7 @@#include <net/sock.h> #include <net/tcp_states.h> #include <trace/events/skb.h> +#include <net/ll_poll.h> /* * Is a socket 'connection oriented' ?
@@ -207,6 +208,9 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags, }spin_unlock_irqrestore (&queue->lock, cpu_flags); +if (sk_valid_ll (sk) &&sk_poll_ll (sk, flags &MSG_DONTWAIT )) +continue ; +/* User doesn't want to wait */ error = -EAGAIN ;if (!timeo)
net/core/skbuff.c +4 -0
@@ -739,6 +739,10 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old) new->vlan_tci = old->vlan_tci;skb_copy_secmark (new, old); + +#ifdef CONFIG_NET_LL_RX_POLL + new->napi_id = old->napi_id; +#endif }/*
net/core/sock.c +6 -0
@@ -139,6 +139,8 @@#include <net/tcp.h> #endif +#include <net/ll_poll.h> +static DEFINE_MUTEX (proto_list_mutex);static LIST_HEAD (proto_list);
@@ -2284,6 +2286,10 @@ void sock_init_data(struct socket *sock, struct sock *sk) sk->sk_stamp =ktime_set (-1L ,0 ); +#ifdef CONFIG_NET_LL_RX_POLL + sk->sk_napi_id =0 ; +#endif +/* * Before updating sk_refcnt, we must commit prior changes to memory * (Documentation/RCU/rculist_nulls.txt for details)
net/core/sysctl_net_core.c +10 -0
@@ -19,6 +19,7 @@#include <net/ip.h> #include <net/sock.h> #include <net/net_ratelimit.h> +#include <net/ll_poll.h> static int one =1 ;
@@ -284,6 +285,15 @@ static struct ctl_table net_core_table[] = { .proc_handler = flow_limit_table_len_sysctl }, #endif /* CONFIG_NET_FLOW_LIMIT */ +#ifdef CONFIG_NET_LL_RX_POLL + { + .procname = "low_latency_poll", + .data = &sysctl_net_ll_poll, + .maxlen = sizeof(unsigned long), + .mode = 0644, + .proc_handler = proc_dointvec + }, +#endif #endif /* CONFIG_NET */ { .procname = "netdev_budget",
net/ipv4/proc.c +1 -0
@@ -273,6 +273,7 @@ static const struct snmp_mib snmp4_net_list[] = {SNMP_MIB_ITEM ("TCPFastOpenListenOverflow" ,LINUX_MIB_TCPFASTOPENLISTENOVERFLOW ),SNMP_MIB_ITEM ("TCPFastOpenCookieReqd" ,LINUX_MIB_TCPFASTOPENCOOKIEREQD ),SNMP_MIB_ITEM ("TCPSpuriousRtxHostQueues" ,LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES ), +SNMP_MIB_ITEM ("LowLatencyRxPackets" ,LINUX_MIB_LOWLATENCYRXPACKETS ), SNMP_MIB_SENTINEL };
net/ipv4/udp.c +5 -1
@@ -109,6 +109,7 @@#include <trace/events/udp.h> #include <linux/static_key.h> #include <trace/events/skb.h> +#include <net/ll_poll.h> #include "udp_impl.h" struct udp_table udp_table__read_mostly ;
@@ -1709,7 +1710,10 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, sk =__udp4_lib_lookup_skb (skb, uh->source, uh->dest, udptable);if (sk !=NULL ) { -int ret =udp_queue_rcv_skb (sk, skb); +int ret; + +sk_mark_ll (sk, skb); + ret =udp_queue_rcv_skb (sk, skb);sock_put (sk);/* a return value > 0 means to resubmit the input, but
net/ipv6/udp.c +5 -1
@@ -46,6 +46,7 @@#include <net/ip6_checksum.h> #include <net/xfrm.h> #include <net/inet6_hashtables.h> +#include <net/ll_poll.h> #include <linux/proc_fs.h> #include <linux/seq_file.h>
@@ -841,7 +842,10 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,*/ sk =__udp6_lib_lookup_skb (skb, uh->source, uh->dest, udptable);if (sk !=NULL ) { -int ret =udpv6_queue_rcv_skb (sk, skb); +int ret; + +sk_mark_ll (sk, skb); + ret =udpv6_queue_rcv_skb (sk, skb);sock_put (sk);/* a return value > 0 means to resubmit the input, but
net/socket.c +15 -1
@@ -104,6 +104,12 @@#include <linux/route.h> #include <linux/sockios.h> #include <linux/atalk.h> +#include <net/ll_poll.h> + +#ifdef CONFIG_NET_LL_RX_POLL +unsigned long sysctl_net_ll_poll__read_mostly ; +EXPORT_SYMBOL_GPL (sysctl_net_ll_poll); +#endif static int sock_no_open (struct inode *irrelevant,struct file *dontcare); static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov,
@@ -1142,13 +1148,21 @@ EXPORT_SYMBOL(sock_create_lite);/* No kernel lock held - perfect */ static unsigned int sock_poll (struct file *file,poll_table *wait) { +unsigned int poll_result;struct socket *sock;/* * We can't return errors to poll, so it's either yes or no. */ sock = file->private_data; -return sock->ops->poll (file, sock, wait); + + poll_result = sock->ops->poll (file, sock, wait); + +if (!(poll_result & (POLLRDNORM |POLLERR |POLLRDHUP |POLLHUP )) && +sk_valid_ll (sock->sk) &&sk_poll_ll (sock->sk,1 )) + poll_result = sock->ops->poll (file, sock,NULL ); + +return poll_result; }static int sock_mmap (struct file *file,struct vm_area_struct *vma)
------------------------------------------------------------------------------
Introducing AppDynamics Lite, a free troubleshooting tool for Java/.NET
Get 100% visibility into your production application - at no cost.
Code-level diagnostics for performance bottlenecks with <2% overhead
Download for free and get started troubleshooting in minutes.
http://p.sf.net/sfu/appdyn_d2d_ap1
_______________________________________________
E1000-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/e1000-devel
To learn more about Intel® Ethernet, visit http://communities.intel.com/community/wired
Re: [PATCH v7 net-next 2/5] net: implement support for low latency socket polling
Quoted 21 lines · Eliezer Tamir
fs/select.c +2
-0@@ -27,6 +27,7 @@#include <linux/rcupdate.h> #include <linux/hrtimer.h> #include <linux/sched/rt.h> +#include <net/ll_poll.h> #include <asm/uaccess.h> @@ -400,6 +401,7 @@ int do_select(int n, fd_set_bits *fds, struct timespec *end_time)poll_table *wait;int retval, i, timed_out =0 ;unsigned long slack =0 ; +cycles_t ll_time =ll_end_time ();rcu_read_lock (); retval =max_select_fd (n, fds);
fs/select.c int do_select(int n, fd_set_bits *fds, struct timespec *end_time) · line 492
Quoted 5 lines
fs/select.c +2
-0@@ -486,6 +488,8 @@ int do_select(int n, fd_set_bits *fds, struct timespec *end_time)break ; } +if (can_poll_ll (ll_time)) +continue ;
I don't see here discrimination between sockets that you want to poll and other sockets.
So it means that select will busy poll every type of file descriptor instead of going to sleep.
Should have a condition with something like sk_valid_ll()
Quoted 3 lines
fs/select.c +0
-0/* * If this is the first loop and we have a timeout * given, then we convert to ktime_t and set the to
...
fs/select.c
Quoted 5 lines
fs/select.c +5
-0+static inline void sk_mark_ll (struct sock *sk,struct sk_buff *skb) +{ +} + +static inline bool can_poll_ll (unsigned long end_time)
should use here cycles_t too.
fs/select.c
Quoted 6 lines
fs/select.c +6
-0+{ +return false; +} + +#endif /* CONFIG_NET_LL_RX_POLL */ +#endif /* _LINUX_NET_LL_POLL_H */
Also, something general about this patch. I think you should split out to separate patches all the users of the feature, like you did for TCP. I would suggest small patches for UDP, select and poll.
Thanks,
Amir
Re: [PATCH v7 net-next 2/5] net: implement support for low latency socket polling
Quoted 6 lines · Amir Vadai
Quoted 5 lines · Eliezer Tamir
fs/select.c +0
-0@@ -486,6 +488,8 @@ int do_select(int n, fd_set_bits *fds, struct timespec *end_time)break ; }
Quoted 7 lines
fs/select.c int do_select(int n, fd_set_bits *fds, struct timespec *end_time) · line 492
Quoted 2 lines
fs/select.c +2
-0+if (can_poll_ll (ll_time)) +continue ;I don't see here discrimination between sockets that you want to poll and other sockets.
So it means that select will busy poll every type of file descriptor instead of going to sleep.
Should have a condition with something likesk_valid_ll()
As I said earlier, select and poll are far from complete.
We are working on this.
Right now when you turn this on, all sockets get the same treatment. sk_valid_ll() can't work here, because we don't have a single socket to work with.
At the moment, I think the right way to solve this might be to add new flags to poll.h So that select/poll can signal to sock_poll that it wants to busy-wait and sock_poll can tell select/poll that it has found a socket that can support it.
Remember that the information is dynamic so we can't know in advance which sockets can busy-poll.
If anyone else has a suggestion I would really like to hear it.
Quoted 7 lines
fs/select.c int do_select(int n, fd_set_bits *fds, struct timespec *end_time)
Quoted 6 lines
fs/select.c +5
-0+static inline void sk_mark_ll (struct sock *sk,struct sk_buff *skb) +{ +} + +static inline bool can_poll_ll (unsigned long end_time)should use here
cycles_ttoo.
yes
Quoted 12 lines
fs/select.c
Quoted 7 lines
fs/select.c +6
-0+{ +return false; +} + +#endif /* CONFIG_NET_LL_RX_POLL */ +#endif /* _LINUX_NET_LL_POLL_H */ Also, something general about this patch. I think you should split out to separate patches all the users of the feature, like you did for TCP. I would suggest small patches for UDP, select and poll.
Splitting out the users of the features as you call it will only move out about 30 lines of patch, I think it will make reviewing harder since you will not be able to see the whole picture in one patch. But if anyone else thinks this is a good idea, I will do it.
-Eliezer
------------------------------------------------------------------------------
Introducing AppDynamics Lite, a free troubleshooting tool for Java/.NET
Get 100% visibility into your production application - at no cost.
Code-level diagnostics for performance bottlenecks with <2% overhead
Download for free and get started troubleshooting in minutes.
http://p.sf.net/sfu/appdyn_d2d_ap1
_______________________________________________
E1000-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/e1000-devel
To learn more about Intel® Ethernet, visit http://communities.intel.com/community/wired
PATCH v7 3/5 tcp: add TCP support for low latency receive poll.
In reply to Eliezer TamirAdds busy-poll support for TCP.
Copy the napi_id from an incomming skb to the sk in tcp_v[46]_rcv(). when there is no data in the socket we busy-poll in tcp_recvmsg(). This is a good example of how to add busy-poll support to new protocols.
---
net/ipv4/tcp.c | 5 +++++ net/ipv4/tcp_ipv4.c | 2 ++ net/ipv6/tcp_ipv6.c | 2 ++ 3 files changed, 9 insertions(+), 0 deletions(-)
net/ipv4/tcp.c +5 -0
@@ -279,6 +279,7 @@#include <asm/uaccess.h> #include <asm/ioctls.h> +#include <net/ll_poll.h> int sysctl_tcp_fin_timeout__read_mostly =TCP_FIN_TIMEOUT ;
@@ -1551,6 +1552,10 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,struct sk_buff *skb;u32 urg_hole =0 ; +if (sk_valid_ll (sk) &&skb_queue_empty (&sk->sk_receive_queue) + && (sk->sk_state ==TCP_ESTABLISHED )) +sk_poll_ll (sk, nonblock); +lock_sock (sk); err = -ENOTCONN ;
net/ipv4/tcp_ipv4.c +2 -0
@@ -75,6 +75,7 @@#include <net/netdma.h> #include <net/secure_seq.h> #include <net/tcp_memcontrol.h> +#include <net/ll_poll.h> #include <linux/inet.h> #include <linux/ipv6.h>
@@ -2011,6 +2012,7 @@ process:if (sk_filter (sk, skb)) goto discard_and_relse; +sk_mark_ll (sk, skb); skb->dev =NULL ;bh_lock_sock_nested (sk);
net/ipv6/tcp_ipv6.c +2 -0
@@ -63,6 +63,7 @@#include <net/inet_common.h> #include <net/secure_seq.h> #include <net/tcp_memcontrol.h> +#include <net/ll_poll.h> #include <asm/uaccess.h>
@@ -1498,6 +1499,7 @@ process:if (sk_filter (sk, skb)) goto discard_and_relse; +sk_mark_ll (sk, skb); skb->dev =NULL ;bh_lock_sock_nested (sk);
------------------------------------------------------------------------------
Introducing AppDynamics Lite, a free troubleshooting tool for Java/.NET
Get 100% visibility into your production application - at no cost.
Code-level diagnostics for performance bottlenecks with <2% overhead
Download for free and get started troubleshooting in minutes.
http://p.sf.net/sfu/appdyn_d2d_ap1
_______________________________________________
E1000-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/e1000-devel
To learn more about Intel® Ethernet, visit http://communities.intel.com/community/wired
PATCH v7 4/5 ixgbe: Add support for ndo_ll_poll
In reply to Eliezer TamirAdd the ixgbe driver code implementing ndo_ll_poll.
Adds ndo_ll_poll method and locking between it and the napi poll. When receiving a packet we use skb_mark_ll to record the napi it came from.
---
drivers/net/ethernet/intel/ixgbe/ixgbe.h | 120 +++++++++++++++++++++++++ drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c | 2 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 63 +++++++++++-- 3 files changed, 177 insertions(+), 8 deletions(-)
drivers/net/ethernet/intel/ixgbe/ixgbe.h +120 -0
@@ -52,6 +52,8 @@#include <linux/dca.h> #endif +#include <net/ll_poll.h> +/* common prefix used by pr_<> macros */ #undef pr_fmt#define pr_fmt (fmt) KBUILD_MODNAME ": " fmt
@@ -356,9 +358,127 @@ struct ixgbe_q_vector {struct rcu_head rcu;/* to avoid race with update stats on free */ char name[IFNAMSIZ +9 ]; +#ifdef CONFIG_NET_LL_RX_POLL +unsigned int state; +#define IXGBE_QV_STATE_IDLE 0 +#define IXGBE_QV_STATE_NAPI 1/* NAPI owns this QV */ +#define IXGBE_QV_STATE_POLL 2/* poll owns this QV */ +#define IXGBE_QV_LOCKED (IXGBE_QV_STATE_NAPI | IXGBE_QV_STATE_POLL) +#define IXGBE_QV_STATE_NAPI_YIELD 4/* NAPI yielded this QV */ +#define IXGBE_QV_STATE_POLL_YIELD 8/* poll yielded this QV */ +#define IXGBE_QV_YIELD (IXGBE_QV_STATE_NAPI_YIELD | IXGBE_QV_STATE_POLL_YIELD) +#define IXGBE_QV_USER_PEND (IXGBE_QV_STATE_POLL | IXGBE_QV_STATE_POLL_YIELD) +spinlock_t lock; +#endif /* CONFIG_NET_LL_RX_POLL */ +/* for dynamic allocation of rings associated with this q_vector */ struct ixgbe_ring ring[0 ]____cacheline_internodealigned_in_smp ; }; +#ifdef CONFIG_NET_LL_RX_POLL +static inline void ixgbe_qv_init_lock (struct ixgbe_q_vector *q_vector) +{ + +spin_lock_init (&q_vector->lock); + q_vector->state =IXGBE_QV_STATE_IDLE ; +} + +/* called from the device poll rutine to get ownership of a q_vector */ +static inline int ixgbe_qv_lock_napi (struct ixgbe_q_vector *q_vector) +{ +int rc = true; +spin_lock (&q_vector->lock); +if (q_vector->state &IXGBE_QV_LOCKED ) { +WARN_ON (q_vector->state &IXGBE_QV_STATE_NAPI ); + q_vector->state |=IXGBE_QV_STATE_NAPI_YIELD ; + rc = false; + }else +/* we don't care if someone yielded */ + q_vector->state =IXGBE_QV_STATE_NAPI ; +spin_unlock (&q_vector->lock); +return rc; +} + +/* returns true is someone tried to get the qv while napi had it */ +static inline int ixgbe_qv_unlock_napi (struct ixgbe_q_vector *q_vector) +{ +int rc = false; +spin_lock (&q_vector->lock); +WARN_ON (q_vector->state & (IXGBE_QV_STATE_POLL | +IXGBE_QV_STATE_NAPI_YIELD )); + +if (q_vector->state &IXGBE_QV_STATE_POLL_YIELD ) + rc = true; + q_vector->state =IXGBE_QV_STATE_IDLE ; +spin_unlock (&q_vector->lock); +return rc; +} + +/* called from ixgbe_low_latency_poll() */ +static inline int ixgbe_qv_lock_poll (struct ixgbe_q_vector *q_vector) +{ +int rc = true; +spin_lock_bh (&q_vector->lock); +if ((q_vector->state &IXGBE_QV_LOCKED )) { + q_vector->state |=IXGBE_QV_STATE_POLL_YIELD ; + rc = false; + }else +/* preserve yield marks */ + q_vector->state |=IXGBE_QV_STATE_POLL ; +spin_unlock_bh (&q_vector->lock); +return rc; +} + +/* returns true if someone tried to get the qv while it was locked */ +static inline int ixgbe_qv_unlock_poll (struct ixgbe_q_vector *q_vector) +{ +int rc = false; +spin_lock_bh (&q_vector->lock); +WARN_ON (q_vector->state & (IXGBE_QV_STATE_NAPI )); + +if (q_vector->state &IXGBE_QV_STATE_POLL_YIELD ) + rc = true; + q_vector->state =IXGBE_QV_STATE_IDLE ; +spin_unlock_bh (&q_vector->lock); +return rc; +} + +/* true if a socket is polling, even if it did not get the lock */ +static inline int ixgbe_qv_ll_polling (struct ixgbe_q_vector *q_vector) +{ +WARN_ON (!(q_vector->state &IXGBE_QV_LOCKED )); +return q_vector->state &IXGBE_QV_USER_PEND ; +} +#else /* CONFIG_NET_LL_RX_POLL */ +static inline void ixgbe_qv_init_lock (struct ixgbe_q_vector *q_vector) +{ +} + +static inline int ixgbe_qv_lock_napi (struct ixgbe_q_vector *q_vector) +{ +return true; +} + +static inline int ixgbe_qv_unlock_napi (struct ixgbe_q_vector *q_vector) +{ +return false; +} + +static inline int ixgbe_qv_lock_poll (struct ixgbe_q_vector *q_vector) +{ +return false; +} + +static inline int ixgbe_qv_unlock_poll (struct ixgbe_q_vector *q_vector) +{ +return false; +} + +static inline int ixgbe_qv_ll_polling (struct ixgbe_q_vector *q_vector) +{ +return false; +} +#endif /* CONFIG_NET_LL_RX_POLL */ +#ifdef CONFIG_IXGBE_HWMON #define IXGBE_HWMON_TYPE_LOC 0
drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c +2 -0
@@ -811,6 +811,7 @@ static int ixgbe_alloc_q_vector(struct ixgbe_adapter *adapter,/* initialize NAPI */ netif_napi_add (adapter->netdev, &q_vector->napi, ixgbe_poll,64 ); +napi_hash_add (&q_vector->napi);/* tie q_vector and adapter together */ adapter->q_vector[v_idx] = q_vector;
@@ -931,6 +932,7 @@ static void ixgbe_free_q_vector(struct ixgbe_adapter *adapter, int v_idx) adapter->rx_ring[ring->queue_index] =NULL ; adapter->q_vector[v_idx] =NULL ; +napi_hash_del (&q_vector->napi);netif_napi_del (&q_vector->napi);/*
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +55 -8
123 lines not on this page · raw message
------------------------------------------------------------------------------
Introducing AppDynamics Lite, a free troubleshooting tool for Java/.NET
Get 100% visibility into your production application - at no cost.
Code-level diagnostics for performance bottlenecks with <2% overhead
Download for free and get started troubleshooting in minutes.
http://p.sf.net/sfu/appdyn_d2d_ap1
_______________________________________________
E1000-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/e1000-devel
To learn more about Intel® Ethernet, visit http://communities.intel.com/community/wired
Re: [PATCH v7 net-next 4/5] ixgbe: Add support for ndo_ll_poll
On Thu, May 30, 2013 at 7:41 PM, Eliezer Tamir
<[email protected]> wrote:
....
Quoted 19 lines
drivers/net/ethernet/intel/ixgbe/ixgbe.h +19
-0+#else /* CONFIG_NET_LL_RX_POLL */ +static inline void ixgbe_qv_init_lock (struct ixgbe_q_vector *q_vector) +{ +} + +static inline int ixgbe_qv_lock_napi (struct ixgbe_q_vector *q_vector) +{ +return true; +} + +static inline int ixgbe_qv_unlock_napi (struct ixgbe_q_vector *q_vector) +{ +return false; +} + +static inline int ixgbe_qv_lock_poll (struct ixgbe_q_vector *q_vector) +{ +return false; +}
drivers/net/ethernet/intel/ixgbe/ixgbe.h struct ixgbe_q_vector { · line 479
Quoted 10 lines
drivers/net/ethernet/intel/ixgbe/ixgbe.h +10
-0+ +static inline int ixgbe_qv_unlock_poll (struct ixgbe_q_vector *q_vector) +{ +return false; +} + +static inline int ixgbe_qv_ll_polling (struct ixgbe_q_vector *q_vector) +{ +return false; +}
Then please make them bool.
------------------------------------------------------------------------------
Get 100% visibility into Java/.NET code with AppDynamics Lite
It's a free troubleshooting tool designed for production
Get down to code-level detail for bottlenecks, with <2% overhead.
Download for free and get started troubleshooting in minutes.
http://p.sf.net/sfu/appdyn_d2d_ap2
_______________________________________________
E1000-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/e1000-devel
To learn more about Intel® Ethernet, visit http://communities.intel.com/community/wired
PATCH v7 5/5 ixgbe: add extra stats for ndo_ll_poll
In reply to Eliezer TamirAdd additional statistics to the ixgbe driver for ndo_ll_poll Defined under LL_EXTENDED_STATS
---
drivers/net/ethernet/intel/ixgbe/ixgbe.h | 14 ++++++++ drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 40 ++++++++++++++++++++++ drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 6 +++ 3 files changed, 60 insertions(+), 0 deletions(-)
drivers/net/ethernet/intel/ixgbe/ixgbe.h +14 -0
@@ -54,6 +54,9 @@#include <net/ll_poll.h> +#ifdef CONFIG_NET_LL_RX_POLL +#define LL_EXTENDED_STATS +#endif /* common prefix used by pr_<> macros */ #undef pr_fmt#define pr_fmt (fmt) KBUILD_MODNAME ": " fmt
@@ -184,6 +187,11 @@ struct ixgbe_rx_buffer {struct ixgbe_queue_stats {u64 packets;u64 bytes; +#ifdef LL_EXTENDED_STATS +u64 yields; +u64 misses; +u64 cleaned; +#endif /* LL_EXTENDED_STATS */ };struct ixgbe_tx_queue_stats {
@@ -391,6 +399,9 @@ static inline int ixgbe_qv_lock_napi(struct ixgbe_q_vector *q_vector)WARN_ON (q_vector->state &IXGBE_QV_STATE_NAPI ); q_vector->state |=IXGBE_QV_STATE_NAPI_YIELD ; rc = false; +#ifdef LL_EXTENDED_STATS + q_vector->tx.ring->stats.yields++; +#endif }else /* we don't care if someone yielded */ q_vector->state =IXGBE_QV_STATE_NAPI ;
@@ -421,6 +432,9 @@ static inline int ixgbe_qv_lock_poll(struct ixgbe_q_vector *q_vector)if ((q_vector->state &IXGBE_QV_LOCKED )) { q_vector->state |=IXGBE_QV_STATE_POLL_YIELD ; rc = false; +#ifdef LL_EXTENDED_STATS + q_vector->rx.ring->stats.yields++; +#endif }else /* preserve yield marks */ q_vector->state |=IXGBE_QV_STATE_POLL ;
drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +40 -0
@@ -1054,6 +1054,12 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev, data[i] =0 ; data[i+1 ] =0 ; i +=2 ; +#ifdef LL_EXTENDED_STATS + data[i] =0 ; + data[i+1 ] =0 ; + data[i+2 ] =0 ; + i +=3 ; +#endif continue ; }
@@ -1063,6 +1069,12 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev, data[i+1 ] = ring->stats.bytes; }while (u64_stats_fetch_retry_bh (&ring->syncp, start)); i +=2 ; +#ifdef LL_EXTENDED_STATS + data[i] = ring->stats.yields; + data[i+1 ] = ring->stats.misses; + data[i+2 ] = ring->stats.cleaned; + i +=3 ; +#endif }for (j =0 ; j <IXGBE_NUM_RX_QUEUES ; j++) { ring = adapter->rx_ring[j];
@@ -1070,6 +1082,12 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev, data[i] =0 ; data[i+1 ] =0 ; i +=2 ; +#ifdef LL_EXTENDED_STATS + data[i] =0 ; + data[i+1 ] =0 ; + data[i+2 ] =0 ; + i +=3 ; +#endif continue ; }
@@ -1079,6 +1097,12 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev, data[i+1 ] = ring->stats.bytes; }while (u64_stats_fetch_retry_bh (&ring->syncp, start)); i +=2 ; +#ifdef LL_EXTENDED_STATS + data[i] = ring->stats.yields; + data[i+1 ] = ring->stats.misses; + data[i+2 ] = ring->stats.cleaned; + i +=3 ; +#endif }for (j =0 ; j <IXGBE_MAX_PACKET_BUFFERS ; j++) {
@@ -1115,12 +1139,28 @@ static void ixgbe_get_strings(struct net_device *netdev, u32 stringset, p +=ETH_GSTRING_LEN ;sprintf (p,"tx_queue_%u_bytes" , i); p +=ETH_GSTRING_LEN ; +#ifdef LL_EXTENDED_STATS +sprintf (p,"tx_q_%u_napi_yield" , i); + p +=ETH_GSTRING_LEN ; +sprintf (p,"tx_q_%u_misses" , i); + p +=ETH_GSTRING_LEN ; +sprintf (p,"tx_q_%u_cleaned" , i); + p +=ETH_GSTRING_LEN ; +#endif /* LL_EXTENDED_STATS */ }for (i =0 ; i <IXGBE_NUM_RX_QUEUES ; i++) {sprintf (p,"rx_queue_%u_packets" , i); p +=ETH_GSTRING_LEN ;sprintf (p,"rx_queue_%u_bytes" , i); p +=ETH_GSTRING_LEN ; +#ifdef LL_EXTENDED_STATS +sprintf (p,"rx_q_%u_ll_poll_yield" , i); + p +=ETH_GSTRING_LEN ; +sprintf (p,"rx_q_%u_misses" , i); + p +=ETH_GSTRING_LEN ; +sprintf (p,"rx_q_%u_cleaned" , i); + p +=ETH_GSTRING_LEN ; +#endif /* LL_EXTENDED_STATS */ }for (i =0 ; i <IXGBE_MAX_PACKET_BUFFERS ; i++) {sprintf (p,"tx_pb_%u_pxon" , i);
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +6 -0
@@ -2016,6 +2016,12 @@ static int ixgbe_low_latency_recv(struct napi_struct *napi)ixgbe_for_each_ring (ring, q_vector->rx) { found =ixgbe_clean_rx_irq (q_vector, ring,4 ); +#ifdef LL_EXTENDED_STATS +if (found) + ring->stats.cleaned += found; +else + ring->stats.misses++; +#endif if (found)break ; }
------------------------------------------------------------------------------
Introducing AppDynamics Lite, a free troubleshooting tool for Java/.NET
Get 100% visibility into your production application - at no cost.
Code-level diagnostics for performance bottlenecks with <2% overhead
Download for free and get started troubleshooting in minutes.
http://p.sf.net/sfu/appdyn_d2d_ap1
_______________________________________________
E1000-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/e1000-devel
To learn more about Intel® Ethernet, visit http://communities.intel.com/community/wired
Quoted 10 lines · Eliezer Tamir
more fixes.
Thank you all for your input.-Eliezer
change log:
v7
- suggested by Ben Hutchings and Eric Dumazet:
type fixes, static for globals innet/core.c,
avoidnapi_idcollisions innapi_hash_add()
Dave,
Please tell my how you think I should proceed.
If you think v7 is good enough I can send a cleanup patch for the type fixes that were suggested.
Or I can submit a v8 with those fixes.
Once we are done with what we have so far, I plan on working on adding all the things we think are needed for a fuller implementation. I hope to submit an RFC in a few weeks.
Thanks,
Eliezer
David Miller
maintainerFrom: Eliezer Tamir <[email protected]>
Date: Sun, 02 Jun 2013 17:02:33 +0300
Quoted 1 line
Or I can submit a v8 with those fixes.
Please submit v8