Skip to content

Commit 05b055e

Browse files
francisyyandavem330
authored andcommitted
tcp: instrument tcp sender limits chronographs
This patch implements the skeleton of the TCP chronograph instrumentation on sender side limits: 1) idle (unspec) 2) busy sending data other than 3-4 below 3) rwnd-limited 4) sndbuf-limited The limits are enumerated 'tcp_chrono'. Since a connection in theory can idle forever, we do not track the actual length of this uninteresting idle period. For the rest we track how long the sender spends in each limit. At any point during the life time of a connection, the sender must be in one of the four states. If there are multiple conditions worthy of tracking in a chronograph then the highest priority enum takes precedence over the other conditions. So that if something "more interesting" starts happening, stop the previous chrono and start a new one. The time unit is jiffy(u32) in order to save space in tcp_sock. This implies application must sample the stats no longer than every 49 days of 1ms jiffy. 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 a090994 commit 05b055e

File tree

3 files changed

+49
-2
lines changed

3 files changed

+49
-2
lines changed

include/linux/tcp.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,8 +211,11 @@ struct tcp_sock {
211211
u8 reord; /* reordering detected */
212212
} rack;
213213
u16 advmss; /* Advertised MSS */
214-
u8 rate_app_limited:1, /* rate_{delivered,interval_us} limited? */
215-
unused:7;
214+
u32 chrono_start; /* Start time in jiffies of a TCP chrono */
215+
u32 chrono_stat[3]; /* Time in jiffies for chrono_stat stats */
216+
u8 chrono_type:2, /* current chronograph type */
217+
rate_app_limited:1, /* rate_{delivered,interval_us} limited? */
218+
unused:5;
216219
u8 nonagle : 4,/* Disable Nagle algorithm? */
217220
thin_lto : 1,/* Use linear timeouts for thin streams */
218221
thin_dupack : 1,/* Fast retransmit on first dupack */

include/net/tcp.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1516,6 +1516,20 @@ struct tcp_fastopen_context {
15161516
struct rcu_head rcu;
15171517
};
15181518

1519+
/* Latencies incurred by various limits for a sender. They are
1520+
* chronograph-like stats that are mutually exclusive.
1521+
*/
1522+
enum tcp_chrono {
1523+
TCP_CHRONO_UNSPEC,
1524+
TCP_CHRONO_BUSY, /* Actively sending data (non-empty write queue) */
1525+
TCP_CHRONO_RWND_LIMITED, /* Stalled by insufficient receive window */
1526+
TCP_CHRONO_SNDBUF_LIMITED, /* Stalled by insufficient send buffer */
1527+
__TCP_CHRONO_MAX,
1528+
};
1529+
1530+
void tcp_chrono_start(struct sock *sk, const enum tcp_chrono type);
1531+
void tcp_chrono_stop(struct sock *sk, const enum tcp_chrono type);
1532+
15191533
/* write queue abstraction */
15201534
static inline void tcp_write_queue_purge(struct sock *sk)
15211535
{

net/ipv4/tcp_output.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2081,6 +2081,36 @@ static bool tcp_small_queue_check(struct sock *sk, const struct sk_buff *skb,
20812081
return false;
20822082
}
20832083

2084+
static void tcp_chrono_set(struct tcp_sock *tp, const enum tcp_chrono new)
2085+
{
2086+
const u32 now = tcp_time_stamp;
2087+
2088+
if (tp->chrono_type > TCP_CHRONO_UNSPEC)
2089+
tp->chrono_stat[tp->chrono_type - 1] += now - tp->chrono_start;
2090+
tp->chrono_start = now;
2091+
tp->chrono_type = new;
2092+
}
2093+
2094+
void tcp_chrono_start(struct sock *sk, const enum tcp_chrono type)
2095+
{
2096+
struct tcp_sock *tp = tcp_sk(sk);
2097+
2098+
/* If there are multiple conditions worthy of tracking in a
2099+
* chronograph then the highest priority enum takes precedence over
2100+
* the other conditions. So that if something "more interesting"
2101+
* starts happening, stop the previous chrono and start a new one.
2102+
*/
2103+
if (type > tp->chrono_type)
2104+
tcp_chrono_set(tp, type);
2105+
}
2106+
2107+
void tcp_chrono_stop(struct sock *sk, const enum tcp_chrono type)
2108+
{
2109+
struct tcp_sock *tp = tcp_sk(sk);
2110+
2111+
tcp_chrono_set(tp, TCP_CHRONO_UNSPEC);
2112+
}
2113+
20842114
/* This routine writes packets to the network. It advances the
20852115
* send_head. This happens as incoming acks open up the remote
20862116
* window for us.

0 commit comments

Comments
 (0)