Skip to content

Commit b0f71bd

Browse files
francisyyandavem330
authored andcommitted
tcp: instrument how long TCP is limited by insufficient send buffer
This patch measures the amount of time when TCP runs out of new data to send to the network due to insufficient send buffer, while TCP is still busy delivering (i.e. write queue is not empty). The goal is to indicate either the send buffer autotuning or user SO_SNDBUF setting has resulted network under-utilization. The measurement starts conservatively by checking various conditions to minimize false claims (i.e. under-estimation is more likely). The measurement stops when the SOCK_NOSPACE flag is cleared. But it does not account the time elapsed till the next application write. Also the measurement only starts if the sender is still busy sending data, s.t. the limit accounted is part of the total busy time. Signed-off-by: Francis Yan <francisyyan@gmail.com> Signed-off-by: Yuchung Cheng <ycheng@google.com> Signed-off-by: Soheil Hassas Yeganeh <soheil@google.com> Acked-by: Neal Cardwell <ncardwell@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 5615f88 commit b0f71bd

File tree

3 files changed

+24
-3
lines changed

3 files changed

+24
-3
lines changed

net/ipv4/tcp.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -996,8 +996,11 @@ static ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset,
996996
goto out;
997997
out_err:
998998
/* make sure we wake any epoll edge trigger waiter */
999-
if (unlikely(skb_queue_len(&sk->sk_write_queue) == 0 && err == -EAGAIN))
999+
if (unlikely(skb_queue_len(&sk->sk_write_queue) == 0 &&
1000+
err == -EAGAIN)) {
10001001
sk->sk_write_space(sk);
1002+
tcp_chrono_stop(sk, TCP_CHRONO_SNDBUF_LIMITED);
1003+
}
10011004
return sk_stream_error(sk, flags, err);
10021005
}
10031006

@@ -1331,8 +1334,11 @@ int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
13311334
out_err:
13321335
err = sk_stream_error(sk, flags, err);
13331336
/* make sure we wake any epoll edge trigger waiter */
1334-
if (unlikely(skb_queue_len(&sk->sk_write_queue) == 0 && err == -EAGAIN))
1337+
if (unlikely(skb_queue_len(&sk->sk_write_queue) == 0 &&
1338+
err == -EAGAIN)) {
13351339
sk->sk_write_space(sk);
1340+
tcp_chrono_stop(sk, TCP_CHRONO_SNDBUF_LIMITED);
1341+
}
13361342
release_sock(sk);
13371343
return err;
13381344
}

net/ipv4/tcp_input.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5059,8 +5059,11 @@ static void tcp_check_space(struct sock *sk)
50595059
/* pairs with tcp_poll() */
50605060
smp_mb__after_atomic();
50615061
if (sk->sk_socket &&
5062-
test_bit(SOCK_NOSPACE, &sk->sk_socket->flags))
5062+
test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) {
50635063
tcp_new_space(sk);
5064+
if (!test_bit(SOCK_NOSPACE, &sk->sk_socket->flags))
5065+
tcp_chrono_stop(sk, TCP_CHRONO_SNDBUF_LIMITED);
5066+
}
50645067
}
50655068
}
50665069

net/ipv4/tcp_output.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1514,6 +1514,18 @@ static void tcp_cwnd_validate(struct sock *sk, bool is_cwnd_limited)
15141514
if (sysctl_tcp_slow_start_after_idle &&
15151515
(s32)(tcp_time_stamp - tp->snd_cwnd_stamp) >= inet_csk(sk)->icsk_rto)
15161516
tcp_cwnd_application_limited(sk);
1517+
1518+
/* The following conditions together indicate the starvation
1519+
* is caused by insufficient sender buffer:
1520+
* 1) just sent some data (see tcp_write_xmit)
1521+
* 2) not cwnd limited (this else condition)
1522+
* 3) no more data to send (null tcp_send_head )
1523+
* 4) application is hitting buffer limit (SOCK_NOSPACE)
1524+
*/
1525+
if (!tcp_send_head(sk) && sk->sk_socket &&
1526+
test_bit(SOCK_NOSPACE, &sk->sk_socket->flags) &&
1527+
(1 << sk->sk_state) & (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT))
1528+
tcp_chrono_start(sk, TCP_CHRONO_SNDBUF_LIMITED);
15171529
}
15181530
}
15191531

0 commit comments

Comments
 (0)