diff options
Diffstat (limited to 'net/ipv4/tcp_input.c')
-rw-r--r-- | net/ipv4/tcp_input.c | 64 |
1 files changed, 5 insertions, 59 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index dad3e7eeed94..6886f386464f 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -2879,67 +2879,13 @@ static void tcp_fastretrans_alert(struct sock *sk, const int acked, | |||
2879 | *rexmit = REXMIT_LOST; | 2879 | *rexmit = REXMIT_LOST; |
2880 | } | 2880 | } |
2881 | 2881 | ||
2882 | /* Kathleen Nichols' algorithm for tracking the minimum value of | ||
2883 | * a data stream over some fixed time interval. (E.g., the minimum | ||
2884 | * RTT over the past five minutes.) It uses constant space and constant | ||
2885 | * time per update yet almost always delivers the same minimum as an | ||
2886 | * implementation that has to keep all the data in the window. | ||
2887 | * | ||
2888 | * The algorithm keeps track of the best, 2nd best & 3rd best min | ||
2889 | * values, maintaining an invariant that the measurement time of the | ||
2890 | * n'th best >= n-1'th best. It also makes sure that the three values | ||
2891 | * are widely separated in the time window since that bounds the worse | ||
2892 | * case error when that data is monotonically increasing over the window. | ||
2893 | * | ||
2894 | * Upon getting a new min, we can forget everything earlier because it | ||
2895 | * has no value - the new min is <= everything else in the window by | ||
2896 | * definition and it's the most recent. So we restart fresh on every new min | ||
2897 | * and overwrites 2nd & 3rd choices. The same property holds for 2nd & 3rd | ||
2898 | * best. | ||
2899 | */ | ||
2900 | static void tcp_update_rtt_min(struct sock *sk, u32 rtt_us) | 2882 | static void tcp_update_rtt_min(struct sock *sk, u32 rtt_us) |
2901 | { | 2883 | { |
2902 | const u32 now = tcp_time_stamp, wlen = sysctl_tcp_min_rtt_wlen * HZ; | 2884 | struct tcp_sock *tp = tcp_sk(sk); |
2903 | struct rtt_meas *m = tcp_sk(sk)->rtt_min; | 2885 | u32 wlen = sysctl_tcp_min_rtt_wlen * HZ; |
2904 | struct rtt_meas rttm = { | 2886 | |
2905 | .rtt = likely(rtt_us) ? rtt_us : jiffies_to_usecs(1), | 2887 | minmax_running_min(&tp->rtt_min, wlen, tcp_time_stamp, |
2906 | .ts = now, | 2888 | rtt_us ? : jiffies_to_usecs(1)); |
2907 | }; | ||
2908 | u32 elapsed; | ||
2909 | |||
2910 | /* Check if the new measurement updates the 1st, 2nd, or 3rd choices */ | ||
2911 | if (unlikely(rttm.rtt <= m[0].rtt)) | ||
2912 | m[0] = m[1] = m[2] = rttm; | ||
2913 | else if (rttm.rtt <= m[1].rtt) | ||
2914 | m[1] = m[2] = rttm; | ||
2915 | else if (rttm.rtt <= m[2].rtt) | ||
2916 | m[2] = rttm; | ||
2917 | |||
2918 | elapsed = now - m[0].ts; | ||
2919 | if (unlikely(elapsed > wlen)) { | ||
2920 | /* Passed entire window without a new min so make 2nd choice | ||
2921 | * the new min & 3rd choice the new 2nd. So forth and so on. | ||
2922 | */ | ||
2923 | m[0] = m[1]; | ||
2924 | m[1] = m[2]; | ||
2925 | m[2] = rttm; | ||
2926 | if (now - m[0].ts > wlen) { | ||
2927 | m[0] = m[1]; | ||
2928 | m[1] = rttm; | ||
2929 | if (now - m[0].ts > wlen) | ||
2930 | m[0] = rttm; | ||
2931 | } | ||
2932 | } else if (m[1].ts == m[0].ts && elapsed > wlen / 4) { | ||
2933 | /* Passed a quarter of the window without a new min so | ||
2934 | * take 2nd choice from the 2nd quarter of the window. | ||
2935 | */ | ||
2936 | m[2] = m[1] = rttm; | ||
2937 | } else if (m[2].ts == m[1].ts && elapsed > wlen / 2) { | ||
2938 | /* Passed half the window without a new min so take the 3rd | ||
2939 | * choice from the last half of the window. | ||
2940 | */ | ||
2941 | m[2] = rttm; | ||
2942 | } | ||
2943 | } | 2889 | } |
2944 | 2890 | ||
2945 | static inline bool tcp_ack_update_rtt(struct sock *sk, const int flag, | 2891 | static inline bool tcp_ack_update_rtt(struct sock *sk, const int flag, |