diff options
author | Eric Dumazet <edumazet@google.com> | 2018-04-16 13:33:37 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-04-16 18:26:37 -0400 |
commit | 03f45c883c6f391ed4fff8292415b35bd1107519 (patch) | |
tree | 826d80967d0b56f08e19072b7fa5810aa03ca667 /net/ipv4/tcp_input.c | |
parent | 796f82eafcd96629c2f9a0332dbb4f474854aaf8 (diff) |
tcp: avoid extra wakeups for SO_RCVLOWAT users
SO_RCVLOWAT is properly handled in tcp_poll(), so that POLLIN is only
generated when enough bytes are available in receive queue, after
David change (commit c7004482e8dc "tcp: Respect SO_RCVLOWAT in tcp_poll().")
But TCP still calls sk->sk_data_ready() for each chunk added in receive
queue, meaning thread is awaken, and goes back to sleep shortly after.
Tested:
tcp_mmap test program, receiving 32768 MB of data with SO_RCVLOWAT set to 512KB
-> Should get ~2 wakeups (c-switches) per MB, regardless of how many
(tiny or big) packets were received.
High speed (mostly full size GRO packets)
received 32768 MB (100 % mmap'ed) in 8.03112 s, 34.2266 Gbit,
cpu usage user:0.037 sys:1.404, 43.9758 usec per MB, 65497 c-switches
received 32768 MB (99.9954 % mmap'ed) in 7.98453 s, 34.4263 Gbit,
cpu usage user:0.03 sys:1.422, 44.3115 usec per MB, 65485 c-switches
Low speed (sender is ratelimited and sends 1-MSS at a time, so GRO is not helping)
received 22474.5 MB (100 % mmap'ed) in 6015.35 s, 0.0313414 Gbit,
cpu usage user:0.05 sys:1.586, 72.7952 usec per MB, 44950 c-switches
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_input.c')
-rw-r--r-- | net/ipv4/tcp_input.c | 15 |
1 files changed, 13 insertions, 2 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index d854363a4387..f93687f97d80 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -4576,6 +4576,17 @@ err: | |||
4576 | 4576 | ||
4577 | } | 4577 | } |
4578 | 4578 | ||
4579 | void tcp_data_ready(struct sock *sk) | ||
4580 | { | ||
4581 | const struct tcp_sock *tp = tcp_sk(sk); | ||
4582 | int avail = tp->rcv_nxt - tp->copied_seq; | ||
4583 | |||
4584 | if (avail < sk->sk_rcvlowat && !sock_flag(sk, SOCK_DONE)) | ||
4585 | return; | ||
4586 | |||
4587 | sk->sk_data_ready(sk); | ||
4588 | } | ||
4589 | |||
4579 | static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) | 4590 | static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) |
4580 | { | 4591 | { |
4581 | struct tcp_sock *tp = tcp_sk(sk); | 4592 | struct tcp_sock *tp = tcp_sk(sk); |
@@ -4633,7 +4644,7 @@ queue_and_out: | |||
4633 | if (eaten > 0) | 4644 | if (eaten > 0) |
4634 | kfree_skb_partial(skb, fragstolen); | 4645 | kfree_skb_partial(skb, fragstolen); |
4635 | if (!sock_flag(sk, SOCK_DEAD)) | 4646 | if (!sock_flag(sk, SOCK_DEAD)) |
4636 | sk->sk_data_ready(sk); | 4647 | tcp_data_ready(sk); |
4637 | return; | 4648 | return; |
4638 | } | 4649 | } |
4639 | 4650 | ||
@@ -5434,7 +5445,7 @@ void tcp_rcv_established(struct sock *sk, struct sk_buff *skb, | |||
5434 | no_ack: | 5445 | no_ack: |
5435 | if (eaten) | 5446 | if (eaten) |
5436 | kfree_skb_partial(skb, fragstolen); | 5447 | kfree_skb_partial(skb, fragstolen); |
5437 | sk->sk_data_ready(sk); | 5448 | tcp_data_ready(sk); |
5438 | return; | 5449 | return; |
5439 | } | 5450 | } |
5440 | } | 5451 | } |