aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2014-09-24 07:11:22 -0400
committerDavid S. Miller <davem@davemloft.net>2014-09-28 16:36:48 -0400
commitcd7d8498c9a5d510c64db38d9f4f4fbc41790f09 (patch)
tree4057e715ca8227a081db71f1ec1359011c5c1a00 /net/ipv4
parentdc83d4d8f6c897022c974a00769b7a6efee6aed8 (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.c4
-rw-r--r--net/ipv4/tcp_input.c8
-rw-r--r--net/ipv4/tcp_output.c9
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 }