donatas abraitis

TCP slow start, is it good or not?

What are we talking about?

tcp_slow_start_after_idle

If set, provide RFC2861 behavior and time out the congestion window after an idle period. An idle period is defined at the current RTO. If unset, the congestion window will not be timed out after an idle period. Default: 1

tcp_no_metrics_save

By default, TCP saves various connection metrics in the route cache when the connection closes, so that connections established in the near future can use these to set initial conditions. Usually, this increases overall performance, but may sometimes cause performance degradation. If set, TCP will not cache metrics on closing connections.

Tests (sent congestion window size)

tcp_slow_start_after_idle=0 and tcp_no_metrics_save=0

count: 16531, min: 5, max: 383, avg: 31

tcp_slow_start_after_idle=1 and tcp_no_metrics_save=0

count: 15250, min: 5, max: 383, avg: 10

tcp_slow_start_after_idle=0 and tcp_no_metrics_save=1

count: 15327, min: 5, max: 383, avg: 24

tcp_slow_start_after_idle=1 and tcp_no_metrics_save=1

count: 15862, min: 5, max: 383, avg: 10

You might wonder how are these numbers obtained?

%{
#include <linux/tcp.h>
%}

global cwnd;
global counter;
global graph = 0;

function get_cwnd:long(sk:long)
%{
        struct tcp_sock *tp = tcp_sk((struct sock *)STAP_ARG_sk);
        if (tp->snd_cwnd)
                THIS->__retvalue = tp->snd_cwnd;
%}

probe kernel.function("tcp_ack").return
{
        cwnd <<< get_cwnd($sk);
        printf("%d\n", get_cwnd($sk));
        if (graph)
                if (counter++ > 500)
                        exit();
}

probe timer.s(30)
{
        printf("count: %d, min: %d, max: %d, avg: %d\n",
                @count(cwnd), @min(cwnd), @max(cwnd), @avg(cwnd));
        exit();
}

Results

Looks like the first case has the best performance, while the second has the worst performance. Even if you have tcp_slow_start_after_idle disabled, enabling tcp_no_metrics_save will win some performance.