From: Daniel Baluta <hidden> Date: 2011-01-27 10:07:51
Hi Tom,
How did you solved the issue regarding scaling TCP listeners?
I think SO_REUSEPORT proposed by patch [1] can be a good
start. Where there any follow ups?
Also, solving the problem in users pace can be an option. I want
to run multiple instances of a DNS server on a multi core system.
Any suggestions would be welcomed.
SO_REUSEPORT option seems to be already there [2]. Where
there any plans to have a kernel implementation?
thanks,
Daniel.
[1] http://amailbox.org/mailarchive/linux-netdev/2010/4/19/6274993
[2] http://lxr.linux.no/linux+v2.6.37/include/asm-generic/socket.h#L25
From: Bill Sommerfeld <hidden> Date: 2011-01-27 15:55:52
On Thu, Jan 27, 2011 at 02:07, Daniel Baluta [off-list ref] wrote:
How did you solved the issue regarding scaling TCP listeners?
I think SO_REUSEPORT proposed by patch [1] can be a good
start. Where there any follow ups?
Google is using the patch internally. I've recently joined google and
have picked up this work from Tom; I'm starting to rework how it
interacts with TCP (in particular, changing how it interacts with
request sockets and listen sockets so that incoming connections are
not prematurely bound to a specific listener sharing the port). I
have nothing worth sharing yet.
From: Tom Herbert <hidden> Date: 2011-01-27 21:32:29
On Thu, Jan 27, 2011 at 2:07 AM, Daniel Baluta [off-list ref] wrote:
Hi Tom,
How did you solved the issue regarding scaling TCP listeners?
I think SO_REUSEPORT proposed by patch [1] can be a good
start. Where there any follow ups?
As Bill mentioned we are continue to work on the TCP issues. Looks
like modifying the TCP listener structures will probably be required.
Also, solving the problem in users pace can be an option. I want
to run multiple instances of a DNS server on a multi core system.
Any suggestions would be welcomed.
SO_REUSEPORT option seems to be already there [2]. Where
there any plans to have a kernel implementation?
Yes, we are still planning this. The UDP implementation for my
earlier patch should be usable to try for DNS/UDP-- this is in fact
where we saw a major performance gain. Eric Dumazet had some nice
improvements that should probably be looked at also.
Tom
From: Thomas Graf <hidden> Date: 2011-02-25 12:56:47
On Thu, Jan 27, 2011 at 01:32:25PM -0800, Tom Herbert wrote:
Yes, we are still planning this. The UDP implementation for my
earlier patch should be usable to try for DNS/UDP-- this is in fact
where we saw a major performance gain. Eric Dumazet had some nice
improvements that should probably be looked at also.
I can confirm this.
Serious scalability issues have been reported on a 12 core system
running bind 9.7-2. The system was only able to deliver ~110K queries
per second.
Using your SO_REUSEPORT patch and a modified bind using it. The same
system is able to deliver ~650K queries per seconds while maxing out
all cores completely.
Tom, Bill: do you have a timeline for merging this? Especially the
UDP bits?
-Thomas
From: Rick Jones <hidden> Date: 2011-02-25 19:18:19
On Fri, 2011-02-25 at 07:56 -0500, Thomas Graf wrote:
On Thu, Jan 27, 2011 at 01:32:25PM -0800, Tom Herbert wrote:
quoted
Yes, we are still planning this. The UDP implementation for my
earlier patch should be usable to try for DNS/UDP-- this is in fact
where we saw a major performance gain. Eric Dumazet had some nice
improvements that should probably be looked at also.
I can confirm this.
Serious scalability issues have been reported on a 12 core system
running bind 9.7-2. The system was only able to deliver ~110K queries
per second.
Using your SO_REUSEPORT patch and a modified bind using it. The same
system is able to deliver ~650K queries per seconds while maxing out
all cores completely.
I think the idea is goodness, but will ask, was the (first) bottleneck
actually in the kernel, or was it in bind itself? I've seen
single-instance, single-byte burst-mode netperf TCP_RR do in excess of
300K transactions per second (with TCP_NODELAY set) on an X5560 core.
ftp://ftp.netperf.org/netperf/misc/dl380g6_X5560_rhel54_ad386_cxgb3_1.4.1.2_b2b_to_same_agg_1500mtu_20100513-2.csv
and that was with now ancient RHEL5.4 bits... yes, there is a bit of
apples, oranges and kumquats but still, I am wondering if this didn't
also "work around" some internal BIND scaling issues as well.
rick jones
Tom, Bill: do you have a timeline for merging this? Especially the
UDP bits?
-Thomas
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
From: David Miller <davem@davemloft.net> Date: 2011-02-25 19:19:43
From: Rick Jones <redacted>
Date: Fri, 25 Feb 2011 11:18:15 -0800
and that was with now ancient RHEL5.4 bits... yes, there is a bit of
apples, oranges and kumquats but still, I am wondering if this didn't
also "work around" some internal BIND scaling issues as well.
I think this is fundamentally a bind problem as well.
From: Eric Dumazet <hidden> Date: 2011-02-25 19:21:39
Le vendredi 25 février 2011 à 11:18 -0800, Rick Jones a écrit :
I think the idea is goodness, but will ask, was the (first) bottleneck
actually in the kernel, or was it in bind itself? I've seen
single-instance, single-byte burst-mode netperf TCP_RR do in excess of
300K transactions per second (with TCP_NODELAY set) on an X5560 core.
ftp://ftp.netperf.org/netperf/misc/dl380g6_X5560_rhel54_ad386_cxgb3_1.4.1.2_b2b_to_same_agg_1500mtu_20100513-2.csv
and that was with now ancient RHEL5.4 bits... yes, there is a bit of
apples, oranges and kumquats but still, I am wondering if this didn't
also "work around" some internal BIND scaling issues as well.
A single core can probably give 300K transactions.
But if you use several cores, accessing a single socket (the one bound
on port 53), then performance drops because of false sharing,
locking....
From: Tom Herbert <hidden> Date: 2011-02-25 19:51:17
Using your SO_REUSEPORT patch and a modified bind using it. The same
system is able to deliver ~650K queries per seconds while maxing out
all cores completely.
Nice data point.
Tom, Bill: do you have a timeline for merging this? Especially the
UDP bits?
Bill has been working on the TCP implementation which is requiring
some fairly major surgery on the listener connections in syn-rcvd
state, this is ongoing.
On the UDP side, I believe the patch is functional, but as Eric
pointed out it probably could be further optimized. I'll split out
the UDP bits into a separate patch and post that...
Tom
From: Thomas Graf <hidden> Date: 2011-02-25 22:48:51
On Fri, Feb 25, 2011 at 11:18:15AM -0800, Rick Jones wrote:
I think the idea is goodness, but will ask, was the (first) bottleneck
actually in the kernel, or was it in bind itself? I've seen
single-instance, single-byte burst-mode netperf TCP_RR do in excess of
300K transactions per second (with TCP_NODELAY set) on an X5560 core.
ftp://ftp.netperf.org/netperf/misc/dl380g6_X5560_rhel54_ad386_cxgb3_1.4.1.2_b2b_to_same_agg_1500mtu_20100513-2.csv
and that was with now ancient RHEL5.4 bits... yes, there is a bit of
apples, oranges and kumquats but still, I am wondering if this didn't
also "work around" some internal BIND scaling issues as well.
Yes it is. We have observed two separate bottlenecks.
The first we have discovered is within BIND. As soon as more than 1
worker thread is being used strace showed a ton of futex() system
calls to the kernel as soon as the number of queries crossed a magic
barrier. This suggested heavy lock contention within BIND.
This BIND lock contetion was not visible on all systems having scalability
issues though. Some machines were not able to deliver enough queries to
BIND in order for the lock contention to appear.
From: Thomas Graf <hidden> Date: 2011-02-25 22:58:36
On Fri, Feb 25, 2011 at 11:51:13AM -0800, Tom Herbert wrote:
On the UDP side, I believe the patch is functional, but as Eric
pointed out it probably could be further optimized. I'll split out
the UDP bits into a separate patch and post that...
Cool! I will be happy to assist in improving it further.
We already see 97-99% CPU utizliation spread evenly over all cores
(with about 20-30% spent in softirq) so at least it already scales
perfectly well.
From: Rick Jones <hidden> Date: 2011-02-25 23:15:05
On Fri, 2011-02-25 at 17:48 -0500, Thomas Graf wrote:
On Fri, Feb 25, 2011 at 11:18:15AM -0800, Rick Jones wrote:
quoted
I think the idea is goodness, but will ask, was the (first) bottleneck
actually in the kernel, or was it in bind itself? I've seen
single-instance, single-byte burst-mode netperf TCP_RR do in excess of
300K transactions per second (with TCP_NODELAY set) on an X5560 core.
ftp://ftp.netperf.org/netperf/misc/dl380g6_X5560_rhel54_ad386_cxgb3_1.4.1.2_b2b_to_same_agg_1500mtu_20100513-2.csv
and that was with now ancient RHEL5.4 bits... yes, there is a bit of
apples, oranges and kumquats but still, I am wondering if this didn't
also "work around" some internal BIND scaling issues as well.
Yes it is. We have observed two separate bottlenecks.
The first we have discovered is within BIND. As soon as more than 1
worker thread is being used strace showed a ton of futex() system
calls to the kernel as soon as the number of queries crossed a magic
barrier. This suggested heavy lock contention within BIND.
The more things change, the more they remain the same, or perhaps "Code
may come and go, but lock contention is forever:
ftp://ftp.cup.hp.com/dist/networking/briefs/bind9_perf.txt
rick jones
The system ftp.cup.hp.com is probably going away before long, I will
probably put its collection of ancient writeups somewhere on netperf.org
This BIND lock contetion was not visible on all systems having scalability
issues though. Some machines were not able to deliver enough queries to
BIND in order for the lock contention to appear.
From: Bill Sommerfeld <hidden> Date: 2011-02-25 23:33:30
On Fri, Feb 25, 2011 at 11:51, Tom Herbert [off-list ref] wrote:
quoted
Tom, Bill: do you have a timeline for merging this? Especially the
UDP bits?
Bill has been working on the TCP implementation which is requiring
some fairly major surgery on the listener connections in syn-rcvd
state, this is ongoing.
Yup. The broad approach I settled on is to delay binding of new
connections to listener sockets by moving receive_sock's from a
per-listen_sock hash table to new hash chains in the global hash
table.
This is very much a work-in-progress. I'm part way through the
conversion and have running code with most of the new structures in
place in parallel with the old; I'm about to start relying exclusively
on the new, and then will tear down the old; once that's done I'll be
in a position to hook that up to SO_REUSEPORT and start actually
measuring the difference. In short: it will be a while.
So splitting SO_REUSEPORT for UDP from SO_REUSEPORT for TCP makes a
lot of sense to me.
From: Herbert Xu <herbert@gondor.apana.org.au> Date: 2011-02-26 00:57:52
David Miller [off-list ref] wrote:
I think this is fundamentally a bind problem as well.
I'm fairly certain the bottleneck is indeed in the kernel, and
in the UDP stack in particular.
This is born out by a test where I used two named worker threads,
both working on the same socket. Stracing shows that they're
working flat out only doing sendmsg/recvmsg.
The result was that they obtained (in aggregate) half the throughput
of a single worker thread.
I then retested by having them use two sockets and the performance
greatly improved.
Now this is actually expected since our UDP stack is essentially
single-threaded on the send side when only one socket is being
used, mostly due to the corking functionality.
I'm unsure how big a role the receive side scalability actually
plays in this case, but I suspect it isn't great.
Which is why I'm quite skeptical about this REUSEPORT patch as
IMHO the only reason it produces a great result is solely because
it is allowing parallel sends going out.
Rather than modifying all UDP applications out there to fix what
is fundamentally a kernel problem, I think what we should do is
fix the UDP stack so that it actually scales.
It isn't all that hard since the easy way would be to only take
the lock if we're already corked or about to cork.
For the receive side we also don't need REUSEPORT as we can simply
make our UDP stack multiqueue.
Cheers,
--
Email: Herbert Xu [off-list ref]
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
From: Herbert Xu <herbert@gondor.apana.org.au> Date: 2011-02-26 02:49:07
On Fri, Feb 25, 2011 at 06:12:44PM -0800, David Miller wrote:
We take the lock unconditionally because we essentially have to after
UDP takes on the socket buffer accounting facilities similar to TCP.
Well I just checked out the history tree (2.6.12) and it too had
the unconditional lock on the send path. So this predates the
system-wide buffer limit change.
I'm looking at redoing this and the bulk of the work is going to
be restructuring ip_append_data/ip_push_pending_frames so that it
doesn't store the states in sk/inet_sk.
Cheers,
--
Email: Herbert Xu [off-list ref]
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
From: David Miller <davem@davemloft.net> Date: 2011-02-26 03:06:46
From: Herbert Xu <herbert@gondor.apana.org.au>
Date: Sat, 26 Feb 2011 10:48:48 +0800
I'm looking at redoing this and the bulk of the work is going to
be restructuring ip_append_data/ip_push_pending_frames so that it
doesn't store the states in sk/inet_sk.
I suppose you're going to replace that stuff with an on-stack
control structure that gets passed around by reference or
similar?
From: Herbert Xu <herbert@gondor.apana.org.au> Date: 2011-02-26 03:11:31
On Fri, Feb 25, 2011 at 07:07:23PM -0800, David Miller wrote:
From: Herbert Xu <herbert@gondor.apana.org.au>
Date: Sat, 26 Feb 2011 10:48:48 +0800
quoted
I'm looking at redoing this and the bulk of the work is going to
be restructuring ip_append_data/ip_push_pending_frames so that it
doesn't store the states in sk/inet_sk.
I suppose you're going to replace that stuff with an on-stack
control structure that gets passed around by reference or
similar?
From: Eric Dumazet <hidden> Date: 2011-02-26 07:31:33
Le samedi 26 février 2011 à 11:11 +0800, Herbert Xu a écrit :
On Fri, Feb 25, 2011 at 07:07:23PM -0800, David Miller wrote:
quoted
From: Herbert Xu <herbert@gondor.apana.org.au>
Date: Sat, 26 Feb 2011 10:48:48 +0800
quoted
I'm looking at redoing this and the bulk of the work is going to
be restructuring ip_append_data/ip_push_pending_frames so that it
doesn't store the states in sk/inet_sk.
I suppose you're going to replace that stuff with an on-stack
control structure that gets passed around by reference or
similar?
Either that or have ip_append_data do ip_push_pending_frames
directly.
That function's signature is a mess already and I need to think
about this a bit more :)
Cheers,
UDP CORK is a problem indeed. I wonder who really uses it ?
From: Thomas Graf <hidden> Date: 2011-02-27 11:02:16
On Sat, Feb 26, 2011 at 08:57:18AM +0800, Herbert Xu wrote:
I'm fairly certain the bottleneck is indeed in the kernel, and
in the UDP stack in particular.
This is born out by a test where I used two named worker threads,
both working on the same socket. Stracing shows that they're
working flat out only doing sendmsg/recvmsg.
The result was that they obtained (in aggregate) half the throughput
of a single worker thread.
I agree. This is the bottleneck that I described were the kernel is
not able to deliver enough queries for BIND to show the lock
contention issues.
But there is also the situation where netperf RR performance numbers
indicate a mugh higher kernel capability but BIND is not able to
deliver more even though the CPU utilization is very low. This is
the situation where we see the large number of futex calls indicating
the lock contention due to too many queries on a single socket.
Which is why I'm quite skeptical about this REUSEPORT patch as
IMHO the only reason it produces a great result is solely because
it is allowing parallel sends going out.
Rather than modifying all UDP applications out there to fix what
is fundamentally a kernel problem, I think what we should do is
fix the UDP stack so that it actually scales.
I am not suggesting that this is the ultimate and final fix for this
problem. It is fixing a symptom rather than fixing the cause but
sometimes being able to fix the symptom becomes really handy :-)
Adding SO_REUSEPORT does not prevent us from fixing the UDP stack
in the long run.
It isn't all that hard since the easy way would be to only take
the lock if we're already corked or about to cork.
For the receive side we also don't need REUSEPORT as we can simply
make our UDP stack multiqueue.
OK, it is not required and there is definitely a better way to fix
the kernel bottleneck in the long term. Even better.
I still suggest to merge this patch as a immediate workaround fix
until we scale properly on a single socket and also as a workaround
for applications which can't get rid of their per socket mutex quickly.
From: Herbert Xu <herbert@gondor.apana.org.au> Date: 2011-02-27 11:06:32
On Sun, Feb 27, 2011 at 06:02:05AM -0500, Thomas Graf wrote:
I still suggest to merge this patch as a immediate workaround fix
until we scale properly on a single socket and also as a workaround
for applications which can't get rid of their per socket mutex quickly.
I disagree completely.
This patch adds a user-space API that we will have to carry
with us for perpetuity. I would only support this if we had
no other way around the problem.
If this does turn out to be mostly due to sendmsg contention
then fixing it is going to be much simpler than making the UDP
stack multiqueue capable.
I'm working on this right now.
Cheers,
--
Email: Herbert Xu [off-list ref]
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
From: Tom Herbert <hidden> Date: 2011-02-28 03:45:59
I disagree completely.
This patch adds a user-space API that we will have to carry
with us for perpetuity. I would only support this if we had
no other way around the problem.
If this does turn out to be mostly due to sendmsg contention
then fixing it is going to be much simpler than making the UDP
stack multiqueue capable.
That sounds promising, but receive side will still have problems.
There is lock contention on the queue as well as cache line bouncing
on the sock structures. Also multiple threads sleeping on same socket
typically leads to asymmetric load across the threads (and
degenerative cases where receiving thread is woken up and other
threads have already processed all the packets). TCP listener threads
suffer from these same problems.
Tom
From: Herbert Xu <herbert@gondor.apana.org.au> Date: 2011-02-28 04:26:34
On Sun, Feb 27, 2011 at 07:45:55PM -0800, Tom Herbert wrote:
That sounds promising, but receive side will still have problems.
There is lock contention on the queue as well as cache line bouncing
on the sock structures. Also multiple threads sleeping on same socket
typically leads to asymmetric load across the threads (and
degenerative cases where receiving thread is woken up and other
threads have already processed all the packets). TCP listener threads
suffer from these same problems.
IOW this is something that we have to solve anyway. I'm just
being overly cautious here because user-space API changes are
something that we should not enter into lightly.
If this patch was completely internal to the kernel, then I would
have much less of an objection as we can always revert/change it
later on. With a user-space API we don't have that flexibility.
Thanks,
--
Email: Herbert Xu [off-list ref]
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
From: Herbert Xu <herbert@gondor.apana.org.au> Date: 2011-02-28 11:37:17
On Sun, Feb 27, 2011 at 07:06:14PM +0800, Herbert Xu wrote:
I'm working on this right now.
OK I think I was definitely on the right track. With the send
patch made lockless I now get numbers which are even better than
those obtained with running named with multiple sockets. That's
right, a single socket is now faster than what multiple sockets
were without the patch (of course, multiple sockets may still
faster with the patch vs. a single socket for obvious reasons,
but I couldn't measure any significant difference).
Also worthy of note is that prior to the patch all CPUs showed
idleness (lazy bastards!), with the patch they're all maxed out.
In retrospect, the idleness was simply the result of the socket
lock scheduling away and was an indication of lock contention.
Here are the patches I used. Please don't them yet as I intend
to clean them up quite a bit.
But please do test them heavily, especially if you have an AMD
NUMA machine as that's where scalability problems really show
up. Intel tends to be a lot more forgiving. My last AMD machine
blew up years ago :)
Thanks!
--
Email: Herbert Xu [off-list ref]
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
From: Herbert Xu <herbert@gondor.apana.org.au> Date: 2011-02-28 11:41:15
inet: Add ip_make_skb and ip_send_skb
This patch adds the helper ip_make_skb which is like ip_append_data
and ip_push_pending_frames all rolled into one, except that it does
not send the skb produced. The sending part is carried out by
ip_send_skb, which the transport protocol can call after it has
tweaked the skb.
It is meant to be called in cases where corking is not used should
have a one-to-one correspondence to sendmsg.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
include/net/ip.h | 8 ++++++
net/ipv4/ip_output.c | 65 ++++++++++++++++++++++++++++++++++++++++-----------
2 files changed, 59 insertions(+), 14 deletions(-)
@@ -1280,7 +1280,6 @@ static int __ip_push_pending_frames(struct sock *sk,structiphdr*iph;__be16df=0;__u8ttl;-interr=0;if((skb=__skb_dequeue(queue))==NULL)gotoout;
@@ -1351,28 +1350,37 @@ static int __ip_push_pending_frames(struct sock *sk,icmp_out_count(net,((structicmphdr*)skb_transport_header(skb))->type);-/* Netfilter gets whole the not fragmented skb. */+ip_cork_release(cork);+out:+returnskb;+}++intip_send_skb(structsk_buff*skb)+{+structnet*net=sock_net(skb->sk);+interr;+err=ip_local_out(skb);if(err){if(err>0)err=net_xmit_errno(err);if(err)-gotoerror;+IP_INC_STATS(net,IPSTATS_MIB_OUTDISCARDS);}-out:-ip_cork_release(cork);returnerr;--error:-IP_INC_STATS(net,IPSTATS_MIB_OUTDISCARDS);-gotoout;}intip_push_pending_frames(structsock*sk){-return__ip_push_pending_frames(sk,&sk->sk_write_queue,-&inet_sk(sk)->cork);+structsk_buff*skb;++skb=__ip_make_skb(sk,&sk->sk_write_queue,&inet_sk(sk)->cork);+if(!skb)+return0;++/* Netfilter gets whole the not fragmented skb. */+returnip_send_skb(skb);}/*
From: Herbert Xu <herbert@gondor.apana.org.au> Date: 2011-02-28 11:41:15
net: Remove unused sk_sndmsg_* from UFO
UFO doesn't really use the sk_sndmsg_* parameters so touching
them is pointless. It can't use them anyway since the whole
point of UFO is to use the original pages without copying.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
net/core/skbuff.c | 3 ---
net/ipv4/ip_output.c | 1 -
net/ipv6/ip6_output.c | 1 -
3 files changed, 5 deletions(-)
@@ -2434,8 +2434,6 @@ int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb,return-ENOMEM;/* initialize the next frag */-sk->sk_sndmsg_page=page;-sk->sk_sndmsg_off=0;skb_fill_page_desc(skb,frg_cnt,page,0,0);skb->truesize+=PAGE_SIZE;atomic_add(PAGE_SIZE,&sk->sk_wmem_alloc);
@@ -2455,7 +2453,6 @@ int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb,return-EFAULT;/* copy was successful so update the size parameters */-sk->sk_sndmsg_off+=copy;frag->size+=copy;skb->len+=copy;skb->data_len+=copy;
@@ -767,7 +767,6 @@ static inline int ip_ufo_append_data(struct sock *sk,skb->ip_summed=CHECKSUM_PARTIAL;skb->csum=0;-sk->sk_sndmsg_off=0;/* specify the length of each IP datagram fragment */skb_shinfo(skb)->gso_size=mtu-fragheaderlen;
From: Herbert Xu <herbert@gondor.apana.org.au> Date: 2011-02-28 11:41:16
udp: Add lockless transmit path
The UDP transmit path has been running under the socket lock
for a long time because of the corking feature. This means that
transmitting to the same socket in multiple threads does not
scale at all.
However, as most users don't actually use corking, the locking
can be removed in the common case.
This patch creates a lockless fast path where corking is not used.
Please note that this does create a slight inaccuracy in the
enforcement of socket send buffer limits. In particular, we
may exceed the socket limit by up to (number of CPUs) * (packet
size) because of the way the limit is computed.
As the primary purpose of socket buffers is to indicate congestion,
this should not be a great problem for now.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
include/net/udp.h | 11 +++++
include/net/udplite.h | 12 +++++
net/ipv4/udp.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 126 insertions(+), 1 deletion(-)
@@ -923,6 +1015,17 @@ back_from_confirm:if(!ipc.addr)daddr=ipc.addr=rt->rt_dst;+/* Lockless fast path for the non-corking case. */+if(!corkreq){+skb=ip_make_skb(sk,getfrag,msg->msg_iov,ulen,+sizeof(structudphdr),&ipc,&rt,+msg->msg_flags);+err=PTR_ERR(skb);+if(skb&&!IS_ERR(skb))+err=udp_send_skb(skb,daddr,dport);+gotoout;+}+lock_sock(sk);if(unlikely(up->pending)){/* The socket is already corked while preparing it. */
From: Herbert Xu <herbert@gondor.apana.org.au> Date: 2011-02-28 11:41:18
net: Remove explicit write references to sk/inet in ip_append_data
In order to allow simultaneous calls to ip_append_data on the same
socket, it must not modify any shared state in sk or inet (other
than those that are designed to allow that such as atomic counters).
This patch abstracts out write references to sk and inet_sk in
ip_append_data and its friends so that we may use the underlying
code in parallel.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
include/net/inet_sock.h | 23 ++--
net/ipv4/ip_output.c | 238 ++++++++++++++++++++++++++++--------------------
2 files changed, 154 insertions(+), 107 deletions(-)
@@ -86,6 +86,19 @@ static inline struct inet_request_sock *inet_rsk(const struct request_sock *sk)return(structinet_request_sock*)sk;}+structinet_cork{+unsignedintflags;+unsignedintfragsize;+structip_options*opt;+structdst_entry*dst;+intlength;/* Total length of all frames */+__be32addr;+structflowifl;+structpage*page;+u32off;+u8tx_flags;+};+structip_mc_socklist;structipv6_pinfo;structrtable;
@@ -143,15 +156,7 @@ struct inet_sock {intmc_index;__be32mc_addr;structip_mc_socklist__rcu*mc_list;-struct{-unsignedintflags;-unsignedintfragsize;-structip_options*opt;-structdst_entry*dst;-intlength;/* Total length of all frames */-__be32addr;-structflowifl;-}cork;+structinet_corkcork;};#define IPCORK_OPT 1 /* ip-options has been held in ipcork.opt */
@@ -733,6 +733,7 @@ csum_page(struct page *page, int offset, int copy)}staticinlineintip_ufo_append_data(structsock*sk,+structsk_buff_head*queue,intgetfrag(void*from,char*to,intoffset,intlen,intodd,structsk_buff*skb),void*from,intlength,inthh_len,intfragheaderlen,
@@ -745,7 +746,7 @@ static inline int ip_ufo_append_data(struct sock *sk,*device,socreateonesingleskbpacketcontainingcomplete*udpdatagram*/-if((skb=skb_peek_tail(&sk->sk_write_queue))==NULL){+if((skb=skb_peek_tail(queue))==NULL){skb=sock_alloc_send_skb(sk,hh_len+fragheaderlen+transhdrlen+20,(flags&MSG_DONTWAIT),&err);
@@ -771,35 +772,24 @@ static inline int ip_ufo_append_data(struct sock *sk,/* specify the length of each IP datagram fragment */skb_shinfo(skb)->gso_size=mtu-fragheaderlen;skb_shinfo(skb)->gso_type=SKB_GSO_UDP;-__skb_queue_tail(&sk->sk_write_queue,skb);+__skb_queue_tail(queue,skb);}returnskb_append_datato_frags(sk,skb,getfrag,from,(length-transhdrlen));}-/*-*ip_append_data()andip_append_page()canmakeonelargeIPdatagram-*frommanypiecesofdata.Eachpieceswillbeholdedonthesocket-*untilip_push_pending_frames()iscalled.Eachpiececanbeapage-*ornon-pagedata.-*-*NotonlyUDP,othertransportprotocols-e.g.rawsockets-canuse-*thisinterfacepotentially.-*-*LATER:lengthmustbeadjustedbypadattail,whenitisrequired.-*/-intip_append_data(structsock*sk,-intgetfrag(void*from,char*to,intoffset,intlen,-intodd,structsk_buff*skb),-void*from,intlength,inttranshdrlen,-structipcm_cookie*ipc,structrtable**rtp,-unsignedintflags)+staticint__ip_append_data(structsock*sk,structsk_buff_head*queue,+structinet_cork*cork,+intgetfrag(void*from,char*to,intoffset,+intlen,intodd,structsk_buff*skb),+void*from,intlength,inttranshdrlen,+unsignedintflags){structinet_sock*inet=inet_sk(sk);structsk_buff*skb;-structip_options*opt=NULL;+structip_options*opt=inet->cork.opt;inthh_len;intexthdrlen;intmtu;
@@ -808,58 +798,19 @@ int ip_append_data(struct sock *sk,intoffset=0;unsignedintmaxfraglen,fragheaderlen;intcsummode=CHECKSUM_NONE;-structrtable*rt;--if(flags&MSG_PROBE)-return0;+structrtable*rt=(structrtable*)cork->dst;-if(skb_queue_empty(&sk->sk_write_queue)){-/*-*setupforcorking.-*/-opt=ipc->opt;-if(opt){-if(inet->cork.opt==NULL){-inet->cork.opt=kmalloc(sizeof(structip_options)+40,sk->sk_allocation);-if(unlikely(inet->cork.opt==NULL))-return-ENOBUFS;-}-memcpy(inet->cork.opt,opt,sizeof(structip_options)+opt->optlen);-inet->cork.flags|=IPCORK_OPT;-inet->cork.addr=ipc->addr;-}-rt=*rtp;-if(unlikely(!rt))-return-EFAULT;-/*-*Westealreferencetothisroute,callershouldnotreleaseit-*/-*rtp=NULL;-inet->cork.fragsize=mtu=inet->pmtudisc==IP_PMTUDISC_PROBE?-rt->dst.dev->mtu:-dst_mtu(rt->dst.path);-inet->cork.dst=&rt->dst;-inet->cork.length=0;-sk->sk_sndmsg_page=NULL;-sk->sk_sndmsg_off=0;-exthdrlen=rt->dst.header_len;-length+=exthdrlen;-transhdrlen+=exthdrlen;-}else{-rt=(structrtable*)inet->cork.dst;-if(inet->cork.flags&IPCORK_OPT)-opt=inet->cork.opt;+exthdrlen=transhdrlen?rt->dst.header_len:0;+length+=exthdrlen;+transhdrlen+=exthdrlen;+mtu=inet->cork.fragsize;-transhdrlen=0;-exthdrlen=0;-mtu=inet->cork.fragsize;-}hh_len=LL_RESERVED_SPACE(rt->dst.dev);fragheaderlen=sizeof(structiphdr)+(opt?opt->optlen:0);maxfraglen=((mtu-fragheaderlen)&~7)+fragheaderlen;-if(inet->cork.length+length>0xFFFF-fragheaderlen){+if(cork->length+length>0xFFFF-fragheaderlen){ip_local_error(sk,EMSGSIZE,rt->rt_dst,inet->inet_dport,mtu-exthdrlen);return-EMSGSIZE;
@@ -875,15 +826,15 @@ int ip_append_data(struct sock *sk,!exthdrlen)csummode=CHECKSUM_PARTIAL;-skb=skb_peek_tail(&sk->sk_write_queue);+skb=skb_peek_tail(queue);-inet->cork.length+=length;+cork->length+=length;if(((length>mtu)||(skb&&skb_is_gso(skb)))&&(sk->sk_protocol==IPPROTO_UDP)&&(rt->dst.dev->features&NETIF_F_UFO)){-err=ip_ufo_append_data(sk,getfrag,from,length,hh_len,-fragheaderlen,transhdrlen,mtu,-flags);+err=ip_ufo_append_data(sk,queue,getfrag,from,length,+hh_len,fragheaderlen,transhdrlen,+mtu,flags);if(err)gotoerror;return0;
@@ -960,7 +911,7 @@ alloc_new_skb:else/* only the initial fragment istimestamped*/-ipc->tx_flags=0;+cork->tx_flags=0;}if(skb==NULL)gotoerror;
@@ -1227,40 +1254,42 @@ error:returnerr;}-staticvoidip_cork_release(structinet_sock*inet)+staticvoidip_cork_release(structinet_cork*cork){-inet->cork.flags&=~IPCORK_OPT;-kfree(inet->cork.opt);-inet->cork.opt=NULL;-dst_release(inet->cork.dst);-inet->cork.dst=NULL;+cork->flags&=~IPCORK_OPT;+kfree(cork->opt);+cork->opt=NULL;+dst_release(cork->dst);+cork->dst=NULL;}/**CombinedallpendingIPfragmentsonthesocketasoneIPdatagram*andpushthemout.*/-intip_push_pending_frames(structsock*sk)+staticint__ip_push_pending_frames(structsock*sk,+structsk_buff_head*queue,+structinet_cork*cork){structsk_buff*skb,*tmp_skb;structsk_buff**tail_skb;structinet_sock*inet=inet_sk(sk);structnet*net=sock_net(sk);structip_options*opt=NULL;-structrtable*rt=(structrtable*)inet->cork.dst;+structrtable*rt=(structrtable*)cork->dst;structiphdr*iph;__be16df=0;__u8ttl;interr=0;-if((skb=__skb_dequeue(&sk->sk_write_queue))==NULL)+if((skb=__skb_dequeue(queue))==NULL)gotoout;tail_skb=&(skb_shinfo(skb)->frag_list);/* move skb->data to ip header from ext header */if(skb->data<skb_network_header(skb))__skb_pull(skb,skb_network_offset(skb));-while((tmp_skb=__skb_dequeue(&sk->sk_write_queue))!=NULL){+while((tmp_skb=__skb_dequeue(queue))!=NULL){__skb_pull(tmp_skb,skb_network_header_len(skb));*tail_skb=tmp_skb;tail_skb=&(tmp_skb->next);
@@ -1286,8 +1315,8 @@ int ip_push_pending_frames(struct sock *sk)ip_dont_fragment(sk,&rt->dst)))df=htons(IP_DF);-if(inet->cork.flags&IPCORK_OPT)-opt=inet->cork.opt;+if(cork->flags&IPCORK_OPT)+opt=cork->opt;if(rt->rt_type==RTN_MULTICAST)ttl=inet->mc_ttl;
@@ -1299,7 +1328,7 @@ int ip_push_pending_frames(struct sock *sk)iph->ihl=5;if(opt){iph->ihl+=opt->optlen>>2;-ip_options_build(skb,opt,inet->cork.addr,rt,0);+ip_options_build(skb,opt,cork->addr,rt,0);}iph->tos=inet->tos;iph->frag_off=df;
@@ -1315,7 +1344,7 @@ int ip_push_pending_frames(struct sock *sk)*Stealrtfromcork.dsttoavoidapairofatomic_inc/atomic_dec*ondstrefcount*/-inet->cork.dst=NULL;+cork->dst=NULL;skb_dst_set(skb,&rt->dst);if(iph->protocol==IPPROTO_ICMP)
@@ -1332,7 +1361,7 @@ int ip_push_pending_frames(struct sock *sk)}out:-ip_cork_release(inet);+ip_cork_release(cork);returnerr;error:
From: Eric Dumazet <hidden> Date: 2011-02-28 13:32:56
Le lundi 28 février 2011 à 19:36 +0800, Herbert Xu a écrit :
On Sun, Feb 27, 2011 at 07:06:14PM +0800, Herbert Xu wrote:
quoted
I'm working on this right now.
OK I think I was definitely on the right track. With the send
patch made lockless I now get numbers which are even better than
those obtained with running named with multiple sockets. That's
right, a single socket is now faster than what multiple sockets
were without the patch (of course, multiple sockets may still
faster with the patch vs. a single socket for obvious reasons,
but I couldn't measure any significant difference).
Also worthy of note is that prior to the patch all CPUs showed
idleness (lazy bastards!), with the patch they're all maxed out.
In retrospect, the idleness was simply the result of the socket
lock scheduling away and was an indication of lock contention.
Now, input path can run without finding socket locked by xmit path, so
skb are queued into receive queue, not backlog one.
Here are the patches I used. Please don't them yet as I intend
to clean them up quite a bit.
But please do test them heavily, especially if you have an AMD
NUMA machine as that's where scalability problems really show
up. Intel tends to be a lot more forgiving. My last AMD machine
blew up years ago :)
From: Thomas Graf <hidden> Date: 2011-02-28 14:13:32
On Mon, Feb 28, 2011 at 07:36:59PM +0800, Herbert Xu wrote:
But please do test them heavily, especially if you have an AMD
NUMA machine as that's where scalability problems really show
up. Intel tends to be a lot more forgiving. My last AMD machine
blew up years ago :)
This is just a preliminary test result and not 100% reliable
because half through the testing the machine reported memory
issues and disabled a DIMM before booting the tested kernels.
Nevertheless, bind 9.7.3:
2.6.38-rc5+: 62kqps
2.6.38-rc5+ w/ Herbert's patch: 442kqps
This is on a 2 NUMA Intel Xeon X5560 @ 2.80GHz with 16 cores
Again, this number is not 100% reliably but clearly shows that
the concept of the patch is working very well.
Will test Herbert's patch on the machine that did 650kqps with
SO_REUSEPORT and also on some AMD machines.
From: Eric Dumazet <hidden> Date: 2011-02-28 14:23:11
Le lundi 28 février 2011 à 22:13 +0800, Herbert Xu a écrit :
On Mon, Feb 28, 2011 at 02:32:51PM +0100, Eric Dumazet wrote:
quoted
Now, input path can run without finding socket locked by xmit path, so
skb are queued into receive queue, not backlog one.
Indeed, I think this is what Dave alluded to earlier. This will
eventually have to be dealt with but for now the data rate is low
enough that it isn't killing us.
Not sure how you read this ;)
I said that before your patches, a sender was consuming lot of time to
transfert frames from backlog to receive queue right before releasing
socket lock.
Now, the receive path doesnt slow down the senders, and vice versa.
:)
From: Herbert Xu <herbert@gondor.apana.org.au> Date: 2011-02-28 14:25:50
On Mon, Feb 28, 2011 at 03:22:06PM +0100, Eric Dumazet wrote:
Not sure how you read this ;)
I said that before your patches, a sender was consuming lot of time to
transfert frames from backlog to receive queue right before releasing
socket lock.
Now, the receive path doesnt slow down the senders, and vice versa.
:)
From: Eric Dumazet <hidden> Date: 2011-02-28 14:55:15
Le lundi 28 février 2011 à 14:32 +0100, Eric Dumazet a écrit :
Le lundi 28 février 2011 à 19:36 +0800, Herbert Xu a écrit :
quoted
On Sun, Feb 27, 2011 at 07:06:14PM +0800, Herbert Xu wrote:
quoted
I'm working on this right now.
OK I think I was definitely on the right track. With the send
patch made lockless I now get numbers which are even better than
those obtained with running named with multiple sockets. That's
right, a single socket is now faster than what multiple sockets
were without the patch (of course, multiple sockets may still
faster with the patch vs. a single socket for obvious reasons,
but I couldn't measure any significant difference).
Also worthy of note is that prior to the patch all CPUs showed
idleness (lazy bastards!), with the patch they're all maxed out.
In retrospect, the idleness was simply the result of the socket
lock scheduling away and was an indication of lock contention.
Now, input path can run without finding socket locked by xmit path, so
skb are queued into receive queue, not backlog one.
quoted
Here are the patches I used. Please don't them yet as I intend
to clean them up quite a bit.
But please do test them heavily, especially if you have an AMD
NUMA machine as that's where scalability problems really show
up. Intel tends to be a lot more forgiving. My last AMD machine
blew up years ago :)
I am going to test them, thanks !
First "sending only" tests on my 2x4x2 machine (two E5540@2.53GHz, quad
core, hyper threaded, NUMA kernel)
16 threads, each one sending 100.000 UDP frames using a _shared_ socket
I use the same destination IP, so suffer a bit of dst refcount
contention.
(to dummy0 device to avoid contention on qdisc and device)
# ip ro get 10.2.2.21
10.2.2.21 dev dummy0 src 10.2.2.2
cache
LOCKDEP enabled kernel
Before :
time ./udpflood -f -t 16 -l 100000 10.2.2.21
real 0m42.749s
user 0m1.010s
sys 1m38.039s
After :
time ./udpflood -f -t 16 -l 100000 10.2.2.21
real 0m1.167s
user 0m0.488s
sys 0m17.373s
With one thread only and 16*100000 frames :
# time ./udpflood -f -l 1600000 10.2.2.21
real 0m9.318s
user 0m0.238s
sys 0m9.052s
(We have some false sharing on atomic fields in struct file and socket,
but nothing to worry about.)
With LOCKDEP OFF :
16 threads :
# time ./udpflood -f -t 16 -l 100000 10.2.2.21
real 0m0.718s
user 0m0.376s
sys 0m10.963s
1 thread :
# time ./udpflood -f -l 1600000 10.2.2.21
real 0m1.514s
user 0m0.153s
sys 0m1.357s
"perf record/report" results for the 16 threads case (no lockdep)
# Events: 389K cpu-clock-msecs
#
# Overhead Command Shared Object Symbol
# ........ ........... ................... ...................................
#
9.03% udpflood [kernel.kallsyms] [k] sock_wfree
8.58% udpflood [kernel.kallsyms] [k] __ip_route_output_key
8.52% udpflood [kernel.kallsyms] [k] sock_alloc_send_pskb
7.46% udpflood [kernel.kallsyms] [k] sock_def_write_space
6.76% udpflood [kernel.kallsyms] [k] __xfrm_lookup
6.18% swapper [kernel.kallsyms] [k] acpi_idle_enter_bm
5.66% udpflood [kernel.kallsyms] [k] dst_release
4.96% udpflood [kernel.kallsyms] [k] udp_sendmsg
3.48% udpflood [kernel.kallsyms] [k] fget_light
2.75% udpflood [kernel.kallsyms] [k] sock_tx_timestamp
2.40% udpflood [kernel.kallsyms] [k] __ip_make_skb
2.36% udpflood [kernel.kallsyms] [k] fput
1.87% swapper [kernel.kallsyms] [k] _raw_spin_unlock_irqrestore
1.81% udpflood [kernel.kallsyms] [k] inet_sendmsg
1.53% udpflood [kernel.kallsyms] [k] sys_sendto
1.50% udpflood [kernel.kallsyms] [k] ip_finish_output
1.31% udpflood [kernel.kallsyms] [k] csum_partial_copy_generic
1.30% udpflood udpflood [.] do_thread
1.28% udpflood [kernel.kallsyms] [k] __ip_append_data
1.08% udpflood [kernel.kallsyms] [k] __memset
1.05% udpflood [kernel.kallsyms] [k] ip_route_output_flow
0.91% udpflood [kernel.kallsyms] [k] kfree
0.88% udpflood [vdso] [.] 0xffffe430
0.83% udpflood [kernel.kallsyms] [k] copy_user_generic_string
0.78% udpflood libc-2.3.4.so [.] __GI_memcpy
0.77% udpflood [kernel.kallsyms] [k] ia32_sysenter_target
What do you suggest to perform a bind based test ?
From: Eric Dumazet <hidden> Date: 2011-02-28 16:23:05
Le lundi 28 février 2011 à 09:13 -0500, Thomas Graf a écrit :
On Mon, Feb 28, 2011 at 07:36:59PM +0800, Herbert Xu wrote:
quoted
But please do test them heavily, especially if you have an AMD
NUMA machine as that's where scalability problems really show
up. Intel tends to be a lot more forgiving. My last AMD machine
blew up years ago :)
This is just a preliminary test result and not 100% reliable
because half through the testing the machine reported memory
issues and disabled a DIMM before booting the tested kernels.
Nevertheless, bind 9.7.3:
2.6.38-rc5+: 62kqps
2.6.38-rc5+ w/ Herbert's patch: 442kqps
This is on a 2 NUMA Intel Xeon X5560 @ 2.80GHz with 16 cores
Again, this number is not 100% reliably but clearly shows that
the concept of the patch is working very well.
Will test Herbert's patch on the machine that did 650kqps with
SO_REUSEPORT and also on some AMD machines.
--
I suspect your queryperf input file hits many zones ?
With a single zone, my machine is able to give 250kps : most of the time
is consumed in bind code, dealing with rwlocks and false sharing
things...
(bind-9.7.2-P3)
Using two remote machines to perform queries, on bnx2x adapter, RSS
enabled : two cpus receive UDP frames for the same socket, so we also
hit false sharing in kernel receive path.
---------------------------------------------------------------------------------------------------------------------------------
PerfTop: 558863 irqs/sec kernel:40.8% exact: 0.0% [1000Hz cpu-clock-msecs], (all, 16 CPUs)
---------------------------------------------------------------------------------------------------------------------------------
samples pcnt function DSO
_______ _____ _____________________________ ______________________________________
137175.00 12.4% acpi_idle_enter_bm [kernel.kallsyms]
63784.00 5.8% _raw_spin_unlock_irqrestore [kernel.kallsyms]
54140.00 4.9% isc_rwlock_lock /opt/src/bind-9.7.2-P3/bin/named/named
32682.00 2.9% isc_rwlock_unlock /opt/src/bind-9.7.2-P3/bin/named/named
21823.00 2.0% dns_rbt_findnode /opt/src/bind-9.7.2-P3/bin/named/named
20306.00 1.8% __ticket_spin_lock [kernel.kallsyms]
16881.00 1.5% finish_task_switch [kernel.kallsyms]
15335.00 1.4% zone_find /opt/src/bind-9.7.2-P3/bin/named/named
14082.00 1.3% decrement_reference /opt/src/bind-9.7.2-P3/bin/named/named
14064.00 1.3% __pthread_mutex_lock_internal /lib/tls/libpthread-2.3.4.so
13519.00 1.2% isc_stats_increment /opt/src/bind-9.7.2-P3/bin/named/named
13027.00 1.2% __GI_memcpy /lib/tls/libc-2.3.4.so
12516.00 1.1% dns_name_concatenate /opt/src/bind-9.7.2-P3/bin/named/named
12499.00 1.1% currentversion /opt/src/bind-9.7.2-P3/bin/named/named
11412.00 1.0% dns_name_fullcompare /opt/src/bind-9.7.2-P3/bin/named/named
10814.00 1.0% new_reference.clone.6 /opt/src/bind-9.7.2-P3/bin/named/named
10580.00 1.0% attach /opt/src/bind-9.7.2-P3/bin/named/named
9805.00 0.9% zone_zonecut_callback /opt/src/bind-9.7.2-P3/bin/named/named
From: Thomas Graf <hidden> Date: 2011-02-28 16:37:48
On Mon, Feb 28, 2011 at 05:22:54PM +0100, Eric Dumazet wrote:
Le lundi 28 février 2011 à 09:13 -0500, Thomas Graf a écrit :
quoted
On Mon, Feb 28, 2011 at 07:36:59PM +0800, Herbert Xu wrote:
quoted
But please do test them heavily, especially if you have an AMD
NUMA machine as that's where scalability problems really show
up. Intel tends to be a lot more forgiving. My last AMD machine
blew up years ago :)
This is just a preliminary test result and not 100% reliable
because half through the testing the machine reported memory
issues and disabled a DIMM before booting the tested kernels.
Nevertheless, bind 9.7.3:
2.6.38-rc5+: 62kqps
2.6.38-rc5+ w/ Herbert's patch: 442kqps
This is on a 2 NUMA Intel Xeon X5560 @ 2.80GHz with 16 cores
Again, this number is not 100% reliably but clearly shows that
the concept of the patch is working very well.
Will test Herbert's patch on the machine that did 650kqps with
SO_REUSEPORT and also on some AMD machines.
--
I suspect your queryperf input file hits many zones ?
No, we use a simple example.com zone with host[1-4] A records
resolving to 10.[1-4].0.1
With a single zone, my machine is able to give 250kps : most of the time
is consumed in bind code, dealing with rwlocks and false sharing
things...
(bind-9.7.2-P3)
Using two remote machines to perform queries, on bnx2x adapter, RSS
enabled : two cpus receive UDP frames for the same socket, so we also
hit false sharing in kernel receive path.
How do you measure the qps? The output of queryperf? That is not always
accurate. I run rdnc stats twice and then calculate the qps based on the
counter "queries resulted in successful answer" diff and timestamp diff.
The numbers differ a lot depending on the architecture we test on.
F.e. on a 12 core AMD with 2 NUMA nodes:
2.6.32 named -n 1: 37.0kqps
named: 3.8kqps (yes, no joke, the socket receive buffer is
always full and the kernel drops pkts)
2.6.38-rc5+ with Herbert's patches:
named -n 1: 36.9kqps
named: 222.0kqps
From: Eric Dumazet <hidden> Date: 2011-02-28 17:10:21
Le lundi 28 février 2011 à 11:37 -0500, Thomas Graf a écrit :
How do you measure the qps? The output of queryperf? That is not always
accurate. I run rdnc stats twice and then calculate the qps based on the
counter "queries resulted in successful answer" diff and timestamp diff.
I have some custom ethernet/system monitoring package installed, so I
get packet rates from it.
I appears my two source machines were not fast enough. (One had LOCKDEP
kernel).
I now reach 320 kqps, even if I force NIC interrupts through one cpu
only.
The numbers differ a lot depending on the architecture we test on.
F.e. on a 12 core AMD with 2 NUMA nodes:
2.6.32 named -n 1: 37.0kqps
named: 3.8kqps (yes, no joke, the socket receive buffer is
always full and the kernel drops pkts)
Yes, this old kernel miss commit c377411f2494a93 added in 2.6.35
(net: sk_add_backlog() take rmem_alloc into account)
Quoting the change log :
Under huge stress from a multiqueue/RPS enabled NIC, a single flow udp
receiver can now process ~200.000 pps (instead of ~100 pps before the
patch) on a 8 core machine.
2.6.38-rc5+ with Herbert's patches:
named -n 1: 36.9kqps
named: 222.0kqps
From: Eric Dumazet <hidden> Date: 2011-03-01 05:30:46
Le lundi 28 février 2011 à 19:41 +0800, Herbert Xu a écrit :
udp: Add lockless transmit path
The UDP transmit path has been running under the socket lock
for a long time because of the corking feature. This means that
transmitting to the same socket in multiple threads does not
scale at all.
However, as most users don't actually use corking, the locking
can be removed in the common case.
This patch creates a lockless fast path where corking is not used.
Please note that this does create a slight inaccuracy in the
enforcement of socket send buffer limits. In particular, we
may exceed the socket limit by up to (number of CPUs) * (packet
size) because of the way the limit is computed.
As the primary purpose of socket buffers is to indicate congestion,
this should not be a great problem for now.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
So far I found no obvious problem, and got pretty impressive results.
Acked-by: Eric Dumazet <redacted>
From: Eric Dumazet <hidden> Date: 2011-03-01 05:31:05
Le lundi 28 février 2011 à 19:41 +0800, Herbert Xu a écrit :
net: Remove unused sk_sndmsg_* from UFO
UFO doesn't really use the sk_sndmsg_* parameters so touching
them is pointless. It can't use them anyway since the whole
point of UFO is to use the original pages without copying.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
From: Eric Dumazet <hidden> Date: 2011-03-01 05:31:31
Le lundi 28 février 2011 à 19:41 +0800, Herbert Xu a écrit :
net: Remove explicit write references to sk/inet in ip_append_data
In order to allow simultaneous calls to ip_append_data on the same
socket, it must not modify any shared state in sk or inet (other
than those that are designed to allow that such as atomic counters).
This patch abstracts out write references to sk and inet_sk in
ip_append_data and its friends so that we may use the underlying
code in parallel.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
include/net/inet_sock.h | 23 ++--
net/ipv4/ip_output.c | 238 ++++++++++++++++++++++++++++--------------------
2 files changed, 154 insertions(+), 107 deletions(-)
From: Eric Dumazet <hidden> Date: 2011-03-01 05:31:44
Le lundi 28 février 2011 à 19:41 +0800, Herbert Xu a écrit :
inet: Add ip_make_skb and ip_send_skb
This patch adds the helper ip_make_skb which is like ip_append_data
and ip_push_pending_frames all rolled into one, except that it does
not send the skb produced. The sending part is carried out by
ip_send_skb, which the transport protocol can call after it has
tweaked the skb.
It is meant to be called in cases where corking is not used should
have a one-to-one correspondence to sendmsg.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
From: Eric Dumazet <hidden> Date: 2011-03-01 05:33:26
Le lundi 28 février 2011 à 19:36 +0800, Herbert Xu a écrit :
Here are the patches I used. Please don't them yet as I intend
to clean them up quite a bit.
I assume you mean "please dont commit them" ;)
But please do test them heavily, especially if you have an AMD
NUMA machine as that's where scalability problems really show
up. Intel tends to be a lot more forgiving. My last AMD machine
blew up years ago :)
Same here, My only AMD machine is a desktop class machine, not a server.
From: Thomas Graf <hidden> Date: 2011-03-01 10:20:01
On Mon, Feb 28, 2011 at 06:07:49PM +0100, Eric Dumazet wrote:
quoted
The numbers differ a lot depending on the architecture we test on.
F.e. on a 12 core AMD with 2 NUMA nodes:
2.6.32 named -n 1: 37.0kqps
named: 3.8kqps (yes, no joke, the socket receive buffer is
always full and the kernel drops pkts)
Yes, this old kernel miss commit c377411f2494a93 added in 2.6.35
(net: sk_add_backlog() take rmem_alloc into account)
I retested with net-2.6 w/o Herbert's patch:
named -n 1: 36.9kqps
named: 16.2kqps
quoted
2.6.38-rc5+ with Herbert's patches:
named -n 1: 36.9kqps
named: 222.0kqps
From: Eric Dumazet <hidden> Date: 2011-03-01 10:33:27
Le mardi 01 mars 2011 à 05:19 -0500, Thomas Graf a écrit :
On Mon, Feb 28, 2011 at 06:07:49PM +0100, Eric Dumazet wrote:
quoted
quoted
The numbers differ a lot depending on the architecture we test on.
F.e. on a 12 core AMD with 2 NUMA nodes:
2.6.32 named -n 1: 37.0kqps
named: 3.8kqps (yes, no joke, the socket receive buffer is
always full and the kernel drops pkts)
Yes, this old kernel miss commit c377411f2494a93 added in 2.6.35
(net: sk_add_backlog() take rmem_alloc into account)
I retested with net-2.6 w/o Herbert's patch:
named -n 1: 36.9kqps
named: 16.2kqps
Thats better ;)
You could do "cat /proc/net/udp" to check if drops occur on port 53
socket (last column)
But maybe your queryperf is limited to few queries in flight (default is
20 per queryperf instance)
From: Thomas Graf <hidden> Date: 2011-03-01 11:07:14
On Tue, Mar 01, 2011 at 11:33:22AM +0100, Eric Dumazet wrote:
quoted
I retested with net-2.6 w/o Herbert's patch:
named -n 1: 36.9kqps
named: 16.2kqps
Thats better ;)
You could do "cat /proc/net/udp" to check if drops occur on port 53
socket (last column)
But maybe your queryperf is limited to few queries in flight (default is
20 per queryperf instance)
From: Eric Dumazet <hidden> Date: 2011-03-01 11:13:11
Le mardi 01 mars 2011 à 06:07 -0500, Thomas Graf a écrit :
On Tue, Mar 01, 2011 at 11:33:22AM +0100, Eric Dumazet wrote:
quoted
quoted
I retested with net-2.6 w/o Herbert's patch:
named -n 1: 36.9kqps
named: 16.2kqps
Thats better ;)
You could do "cat /proc/net/udp" to check if drops occur on port 53
socket (last column)
But maybe your queryperf is limited to few queries in flight (default is
20 per queryperf instance)
I tried -q 10, 20, 30, 50, 100. Starting with 20 I see drops, at q=50
queryperf reports 99% drops.
I also tested again on the Intel machine that did ~650kqps using SO_REUSEPORT.
net-2.6: 106.3kqps, 101.2kqps
net-2.6 lockless udp: 251.7kqps, 250.4kqps
I see drops in both test cases occur so I believe the rate supplied by the
clients is sufficient.
The difference is obvious when looking at top and mpstat:
UDP lockless (250kqps):
Cpu0 : 46.4%us, 28.8%sy, 0.0%ni, 24.8%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Cpu1 : 2.0%us, 1.3%sy, 0.0%ni, 3.0%id, 0.0%wa, 0.0%hi, 93.6%si, 0.0%st
Cpu2 : 45.9%us, 28.2%sy, 0.0%ni, 25.9%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Cpu3 : 50.0%us, 21.6%sy, 0.0%ni, 28.4%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Cpu4 : 45.4%us, 27.8%sy, 0.0%ni, 26.5%id, 0.0%wa, 0.0%hi, 0.3%si, 0.0%st
Cpu5 : 50.7%us, 23.2%sy, 0.0%ni, 26.1%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Cpu6 : 45.2%us, 28.9%sy, 0.0%ni, 25.9%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Cpu7 : 50.5%us, 22.0%sy, 0.0%ni, 27.5%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Cpu8 : 45.3%us, 29.3%sy, 0.0%ni, 25.4%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Cpu9 : 50.8%us, 20.8%sy, 0.0%ni, 28.3%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Cpu10 : 46.1%us, 27.8%sy, 0.0%ni, 26.1%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Cpu11 : 27.2%us, 11.3%sy, 0.0%ni, 3.3%id, 0.0%wa, 0.0%hi, 58.1%si, 0.0%st
Its a bit strange two cpus spend time in softirq, unless you have two
queryperf sources, and a multiqueue NIC, or maybe you use two NICS ?
Mind use "perf top -C 1" and "perf top -C 11" to check what these cpus
do ?
CPU 1 handles receives from your BENET NIC
(Its a bit strange, given this NIC should provide 4 rx queues). Load
could be split to two cpus in your case (two sources)
Try :
ethtool -S eth0 | grep rx_pk
rxq0: rx_pkts: ??
rxq1: rx_pkts: ??
rxq2: rx_pkts: ??
rxq3: rx_pkts: ??
rxq4: rx_pkts: ??
Its BE_HDR_LEN being 64, small UDP frames are too big to fit in skb
head.
From: Herbert Xu <herbert@gondor.apana.org.au> Date: 2011-03-01 11:53:28
On Tue, Mar 01, 2011 at 12:45:09PM +0100, Eric Dumazet wrote:
CPU 11 handles all TX completions : Its a potential bottleneck.
I might ressurect XPS patch ;)
Actually this has been my gripe all along with our TX multiqueue
support. We should not decide the queue based on the socket, but
on the current CPU.
We already do the right thing for forwarded packets because there
is no socket to latch onto, we just need to fix it for locally
generated traffic.
The odd packet reordering each time your scheduler decides to
migrate the process isn't a big deal IMHO. If your scheduler
is constantly moving things you've got bigger problems to worry
about.
Cheers,
--
Email: Herbert Xu [off-list ref]
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
From: Herbert Xu <herbert@gondor.apana.org.au> Date: 2011-03-01 12:15:59
On Tue, Mar 01, 2011 at 07:01:12AM -0500, Thomas Graf wrote:
On Tue, Mar 01, 2011 at 12:45:09PM +0100, Eric Dumazet wrote:
This is how perf top looks like with SO_REUSEPORT
Yeah I think Eric is spot on. The remaining bottleneck is because
we hash all outbound packets from a single socket to a single TX
queue, despite the fact that they were produced on difference CPUs.
Cheers,
--
Email: Herbert Xu [off-list ref]
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
From: Herbert Xu <herbert@gondor.apana.org.au> Date: 2011-03-01 12:33:07
On Tue, Mar 01, 2011 at 07:53:05PM +0800, Herbert Xu wrote:
On Tue, Mar 01, 2011 at 12:45:09PM +0100, Eric Dumazet wrote:
quoted
CPU 11 handles all TX completions : Its a potential bottleneck.
I might ressurect XPS patch ;)
Actually this has been my gripe all along with our TX multiqueue
support. We should not decide the queue based on the socket, but
on the current CPU.
We already do the right thing for forwarded packets because there
is no socket to latch onto, we just need to fix it for locally
generated traffic.
The odd packet reordering each time your scheduler decides to
migrate the process isn't a big deal IMHO. If your scheduler
is constantly moving things you've got bigger problems to worry
about.
If anybody wants to play here is a patch to do exactly that:
net: Determine TX queue purely by current CPU
Distributing packets generated on one CPU to multiple queues
makes no sense. Nor does putting packets from multiple CPUs
into a single queue.
While this may introduce packet reordering should the scheduler
decide to migrate a thread, it isn't a big deal because migration
is meant to be a rare event, and nothing will die as long as the
ordering doesn't occur all the time.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
From: Herbert Xu <herbert@gondor.apana.org.au> Date: 2011-03-01 12:35:31
On Mon, Feb 28, 2011 at 07:36:59PM +0800, Herbert Xu wrote:
Here are the patches I used. Please don't them yet as I intend
to clean them up quite a bit.
OK here is the version ready for merging (please retest them
though as I have changed things substantially).
The main change is that the legacy UDP code path is now gone
so we use the same UDP header generation whether corking is on
or off.
I will add IPv6 support in a later patch set.
Thanks!
--
Email: Herbert Xu [off-list ref]
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
From: Herbert Xu <herbert@gondor.apana.org.au> Date: 2011-03-01 12:37:00
udp: Add lockless transmit path
The UDP transmit path has been running under the socket lock
for a long time because of the corking feature. This means that
transmitting to the same socket in multiple threads does not
scale at all.
However, as most users don't actually use corking, the locking
can be removed in the common case.
This patch creates a lockless fast path where corking is not used.
Please note that this does create a slight inaccuracy in the
enforcement of socket send buffer limits. In particular, we
may exceed the socket limit by up to (number of CPUs) * (packet
size) because of the way the limit is computed.
As the primary purpose of socket buffers is to indicate congestion,
this should not be a great problem for now.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
net/ipv4/udp.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
@@ -940,6 +943,17 @@ back_from_confirm:if(!ipc.addr)daddr=ipc.addr=rt->rt_dst;+/* Lockless fast path for the non-corking case. */+if(!corkreq){+skb=ip_make_skb(sk,getfrag,msg->msg_iov,ulen,+sizeof(structudphdr),&ipc,&rt,+msg->msg_flags);+err=PTR_ERR(skb);+if(skb&&!IS_ERR(skb))+err=udp_send_skb(skb,daddr,dport);+gotoout;+}+lock_sock(sk);if(unlikely(up->pending)){/* The socket is already corked while preparing it. */
From: Herbert Xu <herbert@gondor.apana.org.au> Date: 2011-03-01 12:37:00
udp: Switch to ip_finish_skb
This patch converts UDP to use the new ip_finish_skb API. This
would then allows us to more easily use ip_make_skb which allows
UDP to run without a socket lock.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
include/net/udp.h | 11 ++++++
include/net/udplite.h | 12 +++++++
net/ipv4/udp.c | 83 ++++++++++++++++++++++++++++++--------------------
3 files changed, 73 insertions(+), 33 deletions(-)
From: Herbert Xu <herbert@gondor.apana.org.au> Date: 2011-03-01 12:37:00
inet: Remove unused sk_sndmsg_* from UFO
UFO doesn't really use the sk_sndmsg_* parameters so touching
them is pointless. It can't use them anyway since the whole
point of UFO is to use the original pages without copying.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
net/core/skbuff.c | 3 ---
net/ipv4/ip_output.c | 1 -
net/ipv6/ip6_output.c | 1 -
3 files changed, 5 deletions(-)
@@ -2434,8 +2434,6 @@ int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb,return-ENOMEM;/* initialize the next frag */-sk->sk_sndmsg_page=page;-sk->sk_sndmsg_off=0;skb_fill_page_desc(skb,frg_cnt,page,0,0);skb->truesize+=PAGE_SIZE;atomic_add(PAGE_SIZE,&sk->sk_wmem_alloc);
@@ -2455,7 +2453,6 @@ int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb,return-EFAULT;/* copy was successful so update the size parameters */-sk->sk_sndmsg_off+=copy;frag->size+=copy;skb->len+=copy;skb->data_len+=copy;
@@ -767,7 +767,6 @@ static inline int ip_ufo_append_data(struct sock *sk,skb->ip_summed=CHECKSUM_PARTIAL;skb->csum=0;-sk->sk_sndmsg_off=0;/* specify the length of each IP datagram fragment */skb_shinfo(skb)->gso_size=mtu-fragheaderlen;
From: Herbert Xu <herbert@gondor.apana.org.au> Date: 2011-03-01 12:37:01
inet: Add ip_make_skb and ip_finish_skb
This patch adds the helper ip_make_skb which is like ip_append_data
and ip_push_pending_frames all rolled into one, except that it does
not send the skb produced. The sending part is carried out by
ip_send_skb, which the transport protocol can call after it has
tweaked the skb.
It is meant to be called in cases where corking is not used should
have a one-to-one correspondence to sendmsg.
This patch also adds the helper ip_finish_skb which is meant to
be replace ip_push_pending_frames when corking is required.
Previously the protocol stack would peek at the socket write
queue and add its header to the first packet. With ip_finish_skb,
the protocol stack can directly operate on the final skb instead,
just like the non-corking case with ip_make_skb.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
include/net/ip.h | 16 ++++++++++++
net/ipv4/ip_output.c | 65 ++++++++++++++++++++++++++++++++++++++++-----------
2 files changed, 67 insertions(+), 14 deletions(-)
@@ -1280,7 +1280,6 @@ static int __ip_push_pending_frames(struct sock *sk,structiphdr*iph;__be16df=0;__u8ttl;-interr=0;if((skb=__skb_dequeue(queue))==NULL)gotoout;
@@ -1351,28 +1350,37 @@ static int __ip_push_pending_frames(struct sock *sk,icmp_out_count(net,((structicmphdr*)skb_transport_header(skb))->type);-/* Netfilter gets whole the not fragmented skb. */+ip_cork_release(cork);+out:+returnskb;+}++intip_send_skb(structsk_buff*skb)+{+structnet*net=sock_net(skb->sk);+interr;+err=ip_local_out(skb);if(err){if(err>0)err=net_xmit_errno(err);if(err)-gotoerror;+IP_INC_STATS(net,IPSTATS_MIB_OUTDISCARDS);}-out:-ip_cork_release(cork);returnerr;--error:-IP_INC_STATS(net,IPSTATS_MIB_OUTDISCARDS);-gotoout;}intip_push_pending_frames(structsock*sk){-return__ip_push_pending_frames(sk,&sk->sk_write_queue,-&inet_sk(sk)->cork);+structsk_buff*skb;++skb=ip_finish_skb(sk);+if(!skb)+return0;++/* Netfilter gets whole the not fragmented skb. */+returnip_send_skb(skb);}/*
From: Herbert Xu <herbert@gondor.apana.org.au> Date: 2011-03-01 12:37:02
inet: Remove explicit write references to sk/inet in ip_append_data
In order to allow simultaneous calls to ip_append_data on the same
socket, it must not modify any shared state in sk or inet (other
than those that are designed to allow that such as atomic counters).
This patch abstracts out write references to sk and inet_sk in
ip_append_data and its friends so that we may use the underlying
code in parallel.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
include/net/inet_sock.h | 23 ++--
net/ipv4/ip_output.c | 238 ++++++++++++++++++++++++++++--------------------
2 files changed, 154 insertions(+), 107 deletions(-)
@@ -86,6 +86,19 @@ static inline struct inet_request_sock *inet_rsk(const struct request_sock *sk)return(structinet_request_sock*)sk;}+structinet_cork{+unsignedintflags;+unsignedintfragsize;+structip_options*opt;+structdst_entry*dst;+intlength;/* Total length of all frames */+__be32addr;+structflowifl;+structpage*page;+u32off;+u8tx_flags;+};+structip_mc_socklist;structipv6_pinfo;structrtable;
@@ -143,15 +156,7 @@ struct inet_sock {intmc_index;__be32mc_addr;structip_mc_socklist__rcu*mc_list;-struct{-unsignedintflags;-unsignedintfragsize;-structip_options*opt;-structdst_entry*dst;-intlength;/* Total length of all frames */-__be32addr;-structflowifl;-}cork;+structinet_corkcork;};#define IPCORK_OPT 1 /* ip-options has been held in ipcork.opt */
@@ -733,6 +733,7 @@ csum_page(struct page *page, int offset, int copy)}staticinlineintip_ufo_append_data(structsock*sk,+structsk_buff_head*queue,intgetfrag(void*from,char*to,intoffset,intlen,intodd,structsk_buff*skb),void*from,intlength,inthh_len,intfragheaderlen,
@@ -745,7 +746,7 @@ static inline int ip_ufo_append_data(struct sock *sk,*device,socreateonesingleskbpacketcontainingcomplete*udpdatagram*/-if((skb=skb_peek_tail(&sk->sk_write_queue))==NULL){+if((skb=skb_peek_tail(queue))==NULL){skb=sock_alloc_send_skb(sk,hh_len+fragheaderlen+transhdrlen+20,(flags&MSG_DONTWAIT),&err);
@@ -771,35 +772,24 @@ static inline int ip_ufo_append_data(struct sock *sk,/* specify the length of each IP datagram fragment */skb_shinfo(skb)->gso_size=mtu-fragheaderlen;skb_shinfo(skb)->gso_type=SKB_GSO_UDP;-__skb_queue_tail(&sk->sk_write_queue,skb);+__skb_queue_tail(queue,skb);}returnskb_append_datato_frags(sk,skb,getfrag,from,(length-transhdrlen));}-/*-*ip_append_data()andip_append_page()canmakeonelargeIPdatagram-*frommanypiecesofdata.Eachpieceswillbeholdedonthesocket-*untilip_push_pending_frames()iscalled.Eachpiececanbeapage-*ornon-pagedata.-*-*NotonlyUDP,othertransportprotocols-e.g.rawsockets-canuse-*thisinterfacepotentially.-*-*LATER:lengthmustbeadjustedbypadattail,whenitisrequired.-*/-intip_append_data(structsock*sk,-intgetfrag(void*from,char*to,intoffset,intlen,-intodd,structsk_buff*skb),-void*from,intlength,inttranshdrlen,-structipcm_cookie*ipc,structrtable**rtp,-unsignedintflags)+staticint__ip_append_data(structsock*sk,structsk_buff_head*queue,+structinet_cork*cork,+intgetfrag(void*from,char*to,intoffset,+intlen,intodd,structsk_buff*skb),+void*from,intlength,inttranshdrlen,+unsignedintflags){structinet_sock*inet=inet_sk(sk);structsk_buff*skb;-structip_options*opt=NULL;+structip_options*opt=inet->cork.opt;inthh_len;intexthdrlen;intmtu;
@@ -808,58 +798,19 @@ int ip_append_data(struct sock *sk,intoffset=0;unsignedintmaxfraglen,fragheaderlen;intcsummode=CHECKSUM_NONE;-structrtable*rt;--if(flags&MSG_PROBE)-return0;+structrtable*rt=(structrtable*)cork->dst;-if(skb_queue_empty(&sk->sk_write_queue)){-/*-*setupforcorking.-*/-opt=ipc->opt;-if(opt){-if(inet->cork.opt==NULL){-inet->cork.opt=kmalloc(sizeof(structip_options)+40,sk->sk_allocation);-if(unlikely(inet->cork.opt==NULL))-return-ENOBUFS;-}-memcpy(inet->cork.opt,opt,sizeof(structip_options)+opt->optlen);-inet->cork.flags|=IPCORK_OPT;-inet->cork.addr=ipc->addr;-}-rt=*rtp;-if(unlikely(!rt))-return-EFAULT;-/*-*Westealreferencetothisroute,callershouldnotreleaseit-*/-*rtp=NULL;-inet->cork.fragsize=mtu=inet->pmtudisc==IP_PMTUDISC_PROBE?-rt->dst.dev->mtu:-dst_mtu(rt->dst.path);-inet->cork.dst=&rt->dst;-inet->cork.length=0;-sk->sk_sndmsg_page=NULL;-sk->sk_sndmsg_off=0;-exthdrlen=rt->dst.header_len;-length+=exthdrlen;-transhdrlen+=exthdrlen;-}else{-rt=(structrtable*)inet->cork.dst;-if(inet->cork.flags&IPCORK_OPT)-opt=inet->cork.opt;+exthdrlen=transhdrlen?rt->dst.header_len:0;+length+=exthdrlen;+transhdrlen+=exthdrlen;+mtu=inet->cork.fragsize;-transhdrlen=0;-exthdrlen=0;-mtu=inet->cork.fragsize;-}hh_len=LL_RESERVED_SPACE(rt->dst.dev);fragheaderlen=sizeof(structiphdr)+(opt?opt->optlen:0);maxfraglen=((mtu-fragheaderlen)&~7)+fragheaderlen;-if(inet->cork.length+length>0xFFFF-fragheaderlen){+if(cork->length+length>0xFFFF-fragheaderlen){ip_local_error(sk,EMSGSIZE,rt->rt_dst,inet->inet_dport,mtu-exthdrlen);return-EMSGSIZE;
@@ -875,15 +826,15 @@ int ip_append_data(struct sock *sk,!exthdrlen)csummode=CHECKSUM_PARTIAL;-skb=skb_peek_tail(&sk->sk_write_queue);+skb=skb_peek_tail(queue);-inet->cork.length+=length;+cork->length+=length;if(((length>mtu)||(skb&&skb_is_gso(skb)))&&(sk->sk_protocol==IPPROTO_UDP)&&(rt->dst.dev->features&NETIF_F_UFO)){-err=ip_ufo_append_data(sk,getfrag,from,length,hh_len,-fragheaderlen,transhdrlen,mtu,-flags);+err=ip_ufo_append_data(sk,queue,getfrag,from,length,+hh_len,fragheaderlen,transhdrlen,+mtu,flags);if(err)gotoerror;return0;
@@ -960,7 +911,7 @@ alloc_new_skb:else/* only the initial fragment istimestamped*/-ipc->tx_flags=0;+cork->tx_flags=0;}if(skb==NULL)gotoerror;
@@ -1227,40 +1254,42 @@ error:returnerr;}-staticvoidip_cork_release(structinet_sock*inet)+staticvoidip_cork_release(structinet_cork*cork){-inet->cork.flags&=~IPCORK_OPT;-kfree(inet->cork.opt);-inet->cork.opt=NULL;-dst_release(inet->cork.dst);-inet->cork.dst=NULL;+cork->flags&=~IPCORK_OPT;+kfree(cork->opt);+cork->opt=NULL;+dst_release(cork->dst);+cork->dst=NULL;}/**CombinedallpendingIPfragmentsonthesocketasoneIPdatagram*andpushthemout.*/-intip_push_pending_frames(structsock*sk)+staticint__ip_push_pending_frames(structsock*sk,+structsk_buff_head*queue,+structinet_cork*cork){structsk_buff*skb,*tmp_skb;structsk_buff**tail_skb;structinet_sock*inet=inet_sk(sk);structnet*net=sock_net(sk);structip_options*opt=NULL;-structrtable*rt=(structrtable*)inet->cork.dst;+structrtable*rt=(structrtable*)cork->dst;structiphdr*iph;__be16df=0;__u8ttl;interr=0;-if((skb=__skb_dequeue(&sk->sk_write_queue))==NULL)+if((skb=__skb_dequeue(queue))==NULL)gotoout;tail_skb=&(skb_shinfo(skb)->frag_list);/* move skb->data to ip header from ext header */if(skb->data<skb_network_header(skb))__skb_pull(skb,skb_network_offset(skb));-while((tmp_skb=__skb_dequeue(&sk->sk_write_queue))!=NULL){+while((tmp_skb=__skb_dequeue(queue))!=NULL){__skb_pull(tmp_skb,skb_network_header_len(skb));*tail_skb=tmp_skb;tail_skb=&(tmp_skb->next);
@@ -1286,8 +1315,8 @@ int ip_push_pending_frames(struct sock *sk)ip_dont_fragment(sk,&rt->dst)))df=htons(IP_DF);-if(inet->cork.flags&IPCORK_OPT)-opt=inet->cork.opt;+if(cork->flags&IPCORK_OPT)+opt=cork->opt;if(rt->rt_type==RTN_MULTICAST)ttl=inet->mc_ttl;
@@ -1299,7 +1328,7 @@ int ip_push_pending_frames(struct sock *sk)iph->ihl=5;if(opt){iph->ihl+=opt->optlen>>2;-ip_options_build(skb,opt,inet->cork.addr,rt,0);+ip_options_build(skb,opt,cork->addr,rt,0);}iph->tos=inet->tos;iph->frag_off=df;
@@ -1315,7 +1344,7 @@ int ip_push_pending_frames(struct sock *sk)*Stealrtfromcork.dsttoavoidapairofatomic_inc/atomic_dec*ondstrefcount*/-inet->cork.dst=NULL;+cork->dst=NULL;skb_dst_set(skb,&rt->dst);if(iph->protocol==IPPROTO_ICMP)
@@ -1332,7 +1361,7 @@ int ip_push_pending_frames(struct sock *sk)}out:-ip_cork_release(inet);+ip_cork_release(cork);returnerr;error:
From: Eric Dumazet <hidden> Date: 2011-03-01 13:03:34
Le mardi 01 mars 2011 à 19:53 +0800, Herbert Xu a écrit :
On Tue, Mar 01, 2011 at 12:45:09PM +0100, Eric Dumazet wrote:
quoted
CPU 11 handles all TX completions : Its a potential bottleneck.
I might ressurect XPS patch ;)
Actually this has been my gripe all along with our TX multiqueue
support. We should not decide the queue based on the socket, but
on the current CPU.
We already do the right thing for forwarded packets because there
is no socket to latch onto, we just need to fix it for locally
generated traffic.
I believe its now done properly (in net-next-2.6) with commit
4f57c087de9b46182 (net: implement mechanism for HW based QOS)
The odd packet reordering each time your scheduler decides to
migrate the process isn't a big deal IMHO. If your scheduler
is constantly moving things you've got bigger problems to worry
about.
From: Eric Dumazet <hidden> Date: 2011-03-01 13:04:35
Le mardi 01 mars 2011 à 20:32 +0800, Herbert Xu a écrit :
quoted hunk
On Tue, Mar 01, 2011 at 07:53:05PM +0800, Herbert Xu wrote:
quoted
On Tue, Mar 01, 2011 at 12:45:09PM +0100, Eric Dumazet wrote:
quoted
CPU 11 handles all TX completions : Its a potential bottleneck.
I might ressurect XPS patch ;)
Actually this has been my gripe all along with our TX multiqueue
support. We should not decide the queue based on the socket, but
on the current CPU.
We already do the right thing for forwarded packets because there
is no socket to latch onto, we just need to fix it for locally
generated traffic.
The odd packet reordering each time your scheduler decides to
migrate the process isn't a big deal IMHO. If your scheduler
is constantly moving things you've got bigger problems to worry
about.
If anybody wants to play here is a patch to do exactly that:
net: Determine TX queue purely by current CPU
Distributing packets generated on one CPU to multiple queues
makes no sense. Nor does putting packets from multiple CPUs
into a single queue.
While this may introduce packet reordering should the scheduler
decide to migrate a thread, it isn't a big deal because migration
is meant to be a rare event, and nothing will die as long as the
ordering doesn't occur all the time.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
From: Herbert Xu <herbert@gondor.apana.org.au> Date: 2011-03-01 13:18:45
On Tue, Mar 01, 2011 at 02:03:29PM +0100, Eric Dumazet wrote:
I believe its now done properly (in net-next-2.6) with commit
4f57c087de9b46182 (net: implement mechanism for HW based QOS)
Nope, that has nothing to do with this.
quoted
The odd packet reordering each time your scheduler decides to
migrate the process isn't a big deal IMHO. If your scheduler
is constantly moving things you've got bigger problems to worry
about.
Well, BENET has one TX queue anyway...
Interesting. So I wonder which lock is showing up at the top
of the profile with a single socket then. As it's definitely
going away with multiple sockets, that means it's not the TX
queue lock.
Cheers,
--
Email: Herbert Xu [off-list ref]
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
From: Herbert Xu <herbert@gondor.apana.org.au> Date: 2011-03-01 13:27:29
On Tue, Mar 01, 2011 at 07:01:12AM -0500, Thomas Graf wrote:
On Tue, Mar 01, 2011 at 12:45:09PM +0100, Eric Dumazet wrote:
This is how perf top looks like with SO_REUSEPORT
----------------------------------------------------------------------------------------------------------------------------------
PerfTop: 27498 irqs/sec kernel:50.5% exact: 0.0% [1000Hz cpu-clock-msecs], (all, CPU: 1)
----------------------------------------------------------------------------------------------------------------------------------
samples pcnt function DSO
_______ _____ _____________________________ __________________
16464.00 6.0% isc_rwlock_lock libisc.so.62.0.1
15462.00 5.7% intel_idle [kernel.kallsyms]
From: Thomas Graf <hidden> Date: 2011-03-01 13:51:00
On Tue, Mar 01, 2011 at 08:19:51PM +0800, Herbert Xu wrote:
On Tue, Mar 01, 2011 at 07:18:29AM -0500, Thomas Graf wrote:
quoted
... makes it use CPU 5 for rxq2 and the qps goes up from 250kqps to 270kqps
I think the increase here comes from the larger number of packets
in flight more than anything.
The bottleneck is still the TX queue (both software and hardware).
From: Eric Dumazet <hidden> Date: 2011-03-01 13:54:45
Le mardi 01 mars 2011 à 21:18 +0800, Herbert Xu a écrit :
Interesting. So I wonder which lock is showing up at the top
of the profile with a single socket then. As it's definitely
going away with multiple sockets, that means it's not the TX
queue lock.
This CPU also runs named process, so this is socket lock and receive
queue lock.
Named threads all do : recvmsg()/sendmsg() in a loop, so all are waiting
a frame before doing some work.
Because of single receive queue, extra context switches occur (all
threads but one have to sleep again per query)
For about 80 kqps (standard linux-2.6 kernel, no patches), I have
following vmstat output
procs -----------memory---------- ---swap-- -----io---- --system-- ----cpu----
r b swpd free buff cache si so bi bo in cs us sy id wa
4 1 0 2184048 63496 1595056 0 0 0 2060 64592 294528 19 11 67 4
6 1 0 2184040 63496 1595056 0 0 0 1960 64686 293928 19 11 66 4
3 1 0 2184040 63496 1595056 0 0 0 2344 64556 294268 20 11 66 4
4 1 0 2184040 63496 1595056 0 0 0 2400 64626 293859 19 11 67 4
From: Herbert Xu <herbert@gondor.apana.org.au> Date: 2011-03-01 13:58:54
On Tue, Mar 01, 2011 at 02:52:46PM +0100, Eric Dumazet wrote:
Le mardi 01 mars 2011 à 21:18 +0800, Herbert Xu a écrit :
quoted
Interesting. So I wonder which lock is showing up at the top
of the profile with a single socket then. As it's definitely
going away with multiple sockets, that means it's not the TX
queue lock.
This CPU also runs named process, so this is socket lock and receive
queue lock.
From: Eric Dumazet <hidden> Date: 2011-03-01 14:07:08
Le mardi 01 mars 2011 à 08:50 -0500, Thomas Graf a écrit :
On Tue, Mar 01, 2011 at 08:19:51PM +0800, Herbert Xu wrote:
quoted
On Tue, Mar 01, 2011 at 07:18:29AM -0500, Thomas Graf wrote:
quoted
... makes it use CPU 5 for rxq2 and the qps goes up from 250kqps to 270kqps
I think the increase here comes from the larger number of packets
in flight more than anything.
The bottleneck is still the TX queue (both software and hardware).
Disabled netfilter and reran test
Now does ~316kqps (rx was split over 2 queues)
Would be nice to cpu affine named to _not_ run on CPU11, just to
specialize it for TX completions and have softirq time percentage and
"perf top -C 11 " results
Thanks
From: Thomas Graf <hidden> Date: 2011-03-01 14:22:43
On Tue, Mar 01, 2011 at 03:06:59PM +0100, Eric Dumazet wrote:
Would be nice to cpu affine named to _not_ run on CPU11, just to
specialize it for TX completions and have softirq time percentage and
"perf top -C 11 " results
From: Thomas Graf <hidden> Date: 2011-03-01 14:30:57
On Tue, Mar 01, 2011 at 09:22:35AM -0500, Thomas Graf wrote:
On Tue, Mar 01, 2011 at 03:06:59PM +0100, Eric Dumazet wrote:
quoted
Would be nice to cpu affine named to _not_ run on CPU11, just to
specialize it for TX completions and have softirq time percentage and
"perf top -C 11 " results
From: Eric Dumazet <hidden> Date: 2011-03-01 14:52:46
Le mardi 01 mars 2011 à 09:30 -0500, Thomas Graf a écrit :
On Tue, Mar 01, 2011 at 09:22:35AM -0500, Thomas Graf wrote:
quoted
On Tue, Mar 01, 2011 at 03:06:59PM +0100, Eric Dumazet wrote:
quoted
Would be nice to cpu affine named to _not_ run on CPU11, just to
specialize it for TX completions and have softirq time percentage and
"perf top -C 11 " results
From: Thomas Graf <hidden> Date: 2011-03-01 15:08:05
On Tue, Mar 01, 2011 at 03:52:40PM +0100, Eric Dumazet wrote:
Le mardi 01 mars 2011 à 09:30 -0500, Thomas Graf a écrit :
quoted
On Tue, Mar 01, 2011 at 09:22:35AM -0500, Thomas Graf wrote:
quoted
On Tue, Mar 01, 2011 at 03:06:59PM +0100, Eric Dumazet wrote:
quoted
Would be nice to cpu affine named to _not_ run on CPU11, just to
specialize it for TX completions and have softirq time percentage and
"perf top -C 11 " results