diff options
author | Eric Dumazet <edumazet@google.com> | 2014-09-24 07:11:22 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-09-28 16:36:48 -0400 |
commit | cd7d8498c9a5d510c64db38d9f4f4fbc41790f09 (patch) | |
tree | 4057e715ca8227a081db71f1ec1359011c5c1a00 /net/ipv4 | |
parent | dc83d4d8f6c897022c974a00769b7a6efee6aed8 (diff) |
tcp: change tcp_skb_pcount() location
Our goal is to access no more than one cache line access per skb in
a write or receive queue when doing the various walks.
After recent TCP_SKB_CB() reorganizations, it is almost done.
Last part is tcp_skb_pcount() which currently uses
skb_shinfo(skb)->gso_segs, which is a terrible choice, because it needs
3 cache lines in current kernel (skb->head, skb->end, and
shinfo->gso_segs are all in 3 different cache lines, far from skb->cb)
This very simple patch reuses space currently taken by tcp_tw_isn
only in input path, as tcp_skb_pcount is only needed for skb stored in
write queue.
This considerably speeds up tcp_ack(), granted we avoid shinfo->tx_flags
to get SKBTX_ACK_TSTAMP, which seems possible.
This also speeds up all sack processing in general.
This speeds up tcp_sendmsg() because it no longer has to access/dirty
shinfo.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/tcp.c | 4 | ||||
-rw-r--r-- | net/ipv4/tcp_input.c | 8 | ||||
-rw-r--r-- | net/ipv4/tcp_output.c | 9 |
3 files changed, 12 insertions, 9 deletions
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 553b01f52f71..87289e51be00 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
@@ -963,7 +963,7 @@ new_segment: | |||
963 | skb->ip_summed = CHECKSUM_PARTIAL; | 963 | skb->ip_summed = CHECKSUM_PARTIAL; |
964 | tp->write_seq += copy; | 964 | tp->write_seq += copy; |
965 | TCP_SKB_CB(skb)->end_seq += copy; | 965 | TCP_SKB_CB(skb)->end_seq += copy; |
966 | skb_shinfo(skb)->gso_segs = 0; | 966 | tcp_skb_pcount_set(skb, 0); |
967 | 967 | ||
968 | if (!copied) | 968 | if (!copied) |
969 | TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_PSH; | 969 | TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_PSH; |
@@ -1261,7 +1261,7 @@ new_segment: | |||
1261 | 1261 | ||
1262 | tp->write_seq += copy; | 1262 | tp->write_seq += copy; |
1263 | TCP_SKB_CB(skb)->end_seq += copy; | 1263 | TCP_SKB_CB(skb)->end_seq += copy; |
1264 | skb_shinfo(skb)->gso_segs = 0; | 1264 | tcp_skb_pcount_set(skb, 0); |
1265 | 1265 | ||
1266 | from += copy; | 1266 | from += copy; |
1267 | copied += copy; | 1267 | copied += copy; |
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index f3f016a15c5a..2c0af90231cf 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -1295,9 +1295,9 @@ static bool tcp_shifted_skb(struct sock *sk, struct sk_buff *skb, | |||
1295 | TCP_SKB_CB(prev)->end_seq += shifted; | 1295 | TCP_SKB_CB(prev)->end_seq += shifted; |
1296 | TCP_SKB_CB(skb)->seq += shifted; | 1296 | TCP_SKB_CB(skb)->seq += shifted; |
1297 | 1297 | ||
1298 | skb_shinfo(prev)->gso_segs += pcount; | 1298 | tcp_skb_pcount_add(prev, pcount); |
1299 | BUG_ON(skb_shinfo(skb)->gso_segs < pcount); | 1299 | BUG_ON(tcp_skb_pcount(skb) < pcount); |
1300 | skb_shinfo(skb)->gso_segs -= pcount; | 1300 | tcp_skb_pcount_add(skb, -pcount); |
1301 | 1301 | ||
1302 | /* When we're adding to gso_segs == 1, gso_size will be zero, | 1302 | /* When we're adding to gso_segs == 1, gso_size will be zero, |
1303 | * in theory this shouldn't be necessary but as long as DSACK | 1303 | * in theory this shouldn't be necessary but as long as DSACK |
@@ -1310,7 +1310,7 @@ static bool tcp_shifted_skb(struct sock *sk, struct sk_buff *skb, | |||
1310 | } | 1310 | } |
1311 | 1311 | ||
1312 | /* CHECKME: To clear or not to clear? Mimics normal skb currently */ | 1312 | /* CHECKME: To clear or not to clear? Mimics normal skb currently */ |
1313 | if (skb_shinfo(skb)->gso_segs <= 1) { | 1313 | if (tcp_skb_pcount(skb) <= 1) { |
1314 | skb_shinfo(skb)->gso_size = 0; | 1314 | skb_shinfo(skb)->gso_size = 0; |
1315 | skb_shinfo(skb)->gso_type = 0; | 1315 | skb_shinfo(skb)->gso_type = 0; |
1316 | } | 1316 | } |
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index a462fb1db896..4d92703df4c6 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
@@ -384,7 +384,7 @@ static void tcp_init_nondata_skb(struct sk_buff *skb, u32 seq, u8 flags) | |||
384 | TCP_SKB_CB(skb)->tcp_flags = flags; | 384 | TCP_SKB_CB(skb)->tcp_flags = flags; |
385 | TCP_SKB_CB(skb)->sacked = 0; | 385 | TCP_SKB_CB(skb)->sacked = 0; |
386 | 386 | ||
387 | shinfo->gso_segs = 1; | 387 | tcp_skb_pcount_set(skb, 1); |
388 | shinfo->gso_size = 0; | 388 | shinfo->gso_size = 0; |
389 | shinfo->gso_type = 0; | 389 | shinfo->gso_type = 0; |
390 | 390 | ||
@@ -972,6 +972,9 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, | |||
972 | TCP_ADD_STATS(sock_net(sk), TCP_MIB_OUTSEGS, | 972 | TCP_ADD_STATS(sock_net(sk), TCP_MIB_OUTSEGS, |
973 | tcp_skb_pcount(skb)); | 973 | tcp_skb_pcount(skb)); |
974 | 974 | ||
975 | /* OK, its time to fill skb_shinfo(skb)->gso_segs */ | ||
976 | skb_shinfo(skb)->gso_segs = tcp_skb_pcount(skb); | ||
977 | |||
975 | /* Our usage of tstamp should remain private */ | 978 | /* Our usage of tstamp should remain private */ |
976 | skb->tstamp.tv64 = 0; | 979 | skb->tstamp.tv64 = 0; |
977 | 980 | ||
@@ -1019,11 +1022,11 @@ static void tcp_set_skb_tso_segs(const struct sock *sk, struct sk_buff *skb, | |||
1019 | /* Avoid the costly divide in the normal | 1022 | /* Avoid the costly divide in the normal |
1020 | * non-TSO case. | 1023 | * non-TSO case. |
1021 | */ | 1024 | */ |
1022 | shinfo->gso_segs = 1; | 1025 | tcp_skb_pcount_set(skb, 1); |
1023 | shinfo->gso_size = 0; | 1026 | shinfo->gso_size = 0; |
1024 | shinfo->gso_type = 0; | 1027 | shinfo->gso_type = 0; |
1025 | } else { | 1028 | } else { |
1026 | shinfo->gso_segs = DIV_ROUND_UP(skb->len, mss_now); | 1029 | tcp_skb_pcount_set(skb, DIV_ROUND_UP(skb->len, mss_now)); |
1027 | shinfo->gso_size = mss_now; | 1030 | shinfo->gso_size = mss_now; |
1028 | shinfo->gso_type = sk->sk_gso_type; | 1031 | shinfo->gso_type = sk->sk_gso_type; |
1029 | } | 1032 | } |