aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_output.c
diff options
context:
space:
mode:
authorIlpo Järvinen <ilpo.jarvinen@helsinki.fi>2007-11-15 22:50:37 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 17:54:07 -0500
commit68f8353b480e5f2e136c38a511abdbb88eaa8ce2 (patch)
tree3e412890c3caa98619872f15e117daffb68e9edf /net/ipv4/tcp_output.c
parentfd6dad616d4fe2f08d690f25ca76b0102158fb3a (diff)
[TCP]: Rewrite SACK block processing & sack_recv_cache use
Key points of this patch are: - In case new SACK information is advance only type, no skb processing below previously discovered highest point is done - Optimize cases below highest point too since there's no need to always go up to highest point (which is very likely still present in that SACK), this is not entirely true though because I'm dropping the fastpath_skb_hint which could previously optimize those cases even better. Whether that's significant, I'm not too sure. Currently it will provide skipping by walking. Combined with RB-tree, all skipping would become fast too regardless of window size (can be done incrementally later). Previously a number of cases in TCP SACK processing fails to take advantage of costly stored information in sack_recv_cache, most importantly, expected events such as cumulative ACK and new hole ACKs. Processing on such ACKs result in rather long walks building up latencies (which easily gets nasty when window is huge). Those latencies are often completely unnecessary compared with the amount of _new_ information received, usually for cumulative ACK there's no new information at all, yet TCP walks whole queue unnecessary potentially taking a number of costly cache misses on the way, etc.! Since the inclusion of highest_sack, there's a lot information that is very likely redundant (SACK fastpath hint stuff, fackets_out, highest_sack), though there's no ultimate guarantee that they'll remain the same whole the time (in all unearthly scenarios). Take advantage of this knowledge here and drop fastpath hint and use direct access to highest SACKed skb as a replacement. Effectively "special cased" fastpath is dropped. This change adds some complexity to introduce better coveraged "fastpath", though the added complexity should make TCP behave more cache friendly. The current ACK's SACK blocks are compared against each cached block individially and only ranges that are new are then scanned by the high constant walk. For other parts of write queue, even when in previously known part of the SACK blocks, a faster skip function is used (if necessary at all). In addition, whenever possible, TCP fast-forwards to highest_sack skb that was made available by an earlier patch. In typical case, no other things but this fast-forward and mandatory markings after that occur making the access pattern quite similar to the former fastpath "special case". DSACKs are special case that must always be walked. The local to recv_sack_cache copying could be more intelligent w.r.t DSACKs which are likely to be there only once but that is left to a separate patch. Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_output.c')
-rw-r--r--net/ipv4/tcp_output.c14
1 files changed, 1 insertions, 13 deletions
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index ce506af5ce07..030fc69ea217 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -653,9 +653,7 @@ static void tcp_set_skb_tso_segs(struct sock *sk, struct sk_buff *skb, unsigned
653} 653}
654 654
655/* When a modification to fackets out becomes necessary, we need to check 655/* When a modification to fackets out becomes necessary, we need to check
656 * skb is counted to fackets_out or not. Another important thing is to 656 * skb is counted to fackets_out or not.
657 * tweak SACK fastpath hint too as it would overwrite all changes unless
658 * hint is also changed.
659 */ 657 */
660static void tcp_adjust_fackets_out(struct sock *sk, struct sk_buff *skb, 658static void tcp_adjust_fackets_out(struct sock *sk, struct sk_buff *skb,
661 int decr) 659 int decr)
@@ -667,11 +665,6 @@ static void tcp_adjust_fackets_out(struct sock *sk, struct sk_buff *skb,
667 665
668 if (!before(tcp_highest_sack_seq(tp), TCP_SKB_CB(skb)->seq)) 666 if (!before(tcp_highest_sack_seq(tp), TCP_SKB_CB(skb)->seq))
669 tp->fackets_out -= decr; 667 tp->fackets_out -= decr;
670
671 /* cnt_hint is "off-by-one" compared with fackets_out (see sacktag) */
672 if (tp->fastpath_skb_hint != NULL &&
673 after(TCP_SKB_CB(tp->fastpath_skb_hint)->seq, TCP_SKB_CB(skb)->seq))
674 tp->fastpath_cnt_hint -= decr;
675} 668}
676 669
677/* Function to create two new TCP segments. Shrinks the given segment 670/* Function to create two new TCP segments. Shrinks the given segment
@@ -1753,11 +1746,6 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb, int m
1753 1746
1754 /* changed transmit queue under us so clear hints */ 1747 /* changed transmit queue under us so clear hints */
1755 tcp_clear_retrans_hints_partial(tp); 1748 tcp_clear_retrans_hints_partial(tp);
1756 /* manually tune sacktag skb hint */
1757 if (tp->fastpath_skb_hint == next_skb) {
1758 tp->fastpath_skb_hint = skb;
1759 tp->fastpath_cnt_hint -= tcp_skb_pcount(skb);
1760 }
1761 1749
1762 sk_stream_free_skb(sk, next_skb); 1750 sk_stream_free_skb(sk, next_skb);
1763 } 1751 }