1. 程式人生 > >TCP擁塞控制演算法 — CUBIC的補丁(四)

TCP擁塞控制演算法 — CUBIC的補丁(四)

描述

以下是提交者Stephen Hemminger對這個patch的描述:

enable high resolution ack time if needed

This is a refined version of an earlier patch by Lucas Nussbaum.

Cubic needs RTT values in miliseconds. If HZ < 1000 then the values will be too coarse.

程式碼

--- a/net/ipv4/tcp_cubic.c
+++ b/net/ipv4/tcp_cubic.c
@@ -459,6 +459,10 @@ static int __init cubictcp_register(void)
 	/* divide by bic_scale and by constant Srtt (100ms) */
 	do_div(cube_factor, bic_scale * 10);
 
+	/* hystart needs ms clock resolution */
+	if (hystart && HZ < 1000)
+		cubictcp.flags |= TCP_CONG_RTT_STAMP;
+
 	return tcp_register_congestion_control(&cubictcp);
 }

分析

@include/net/tcp.h:
#define TCP_CONG_RTT_STAMP 0x02

struct tcp_congestion_ops {
    ...
    unsigned long flags;
    ...
};

/**
 * @tstamp: Time we arrived
 */
struct sk_buff {
    ...
    ktime_t tstamp;
    ...
};

static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets, u32 prior_snd_una)
{
    ktime_t last_ackt = net_invalid_timestamp();
    ...
        ca_seq_rtt = now - scb->when;
        last_ackt = skb->tstamp;
    ...
    if (ca_ops->pkts_acked) {
        s32 rtt_us = -1;

        /* Is the ACK triggering packet unambiguous? */
        if (! (flag & FLAG_RETRANS_DATA_ACKED)) {
            /* High resolution needed and available? */
            if (ca_ops->flags & TCP_CONG_RTT_STAMP &&
                ! ktime_equal(last_ackt, net_invalid_timestamp()))
                rtt_us = ktime_us_delta(ktime_get_real(), last_ackt); /* 精確到微秒*/

            else if (ca_seq_rtt >= 0)
                rtt_us = jiffies_to_usecs(ca_seq_rtt); /*精確度只有jiffies,一般是毫秒 */
        }
        ca_ops->pkts_acked(sk, pkts_acked, rtt_us);
    }
    ...
}

/**
 * ktime_equal - Compares two ktime_t variables to see if they are equal
 * @cmp1: comparable1
 * @cmp2: comparable2
 * Compare two ktime_t variables, returns 1 if equal
 */
static inline int ktime_equal(const ktime_t cmp1, const ktime_t cmp2)
{
    return cmp1.tv64 == cmp2.tv64;
}

static inline ktime_t net_invalid_timestamp(void)
{
    return ktime_set(0, 0);
}

/* Set a ktime_t variable to a value in sec/nsec representation: */
static inline ktime_t ktime_set (const long secs, const unsigned long nsecs)
{
    return (ktime_t) { .tv = { .sec = secs, .nsec = nsecs} };
}
@tcp_transmit_skb
/* If congestion control is doing timestamping, we must take such a timestamp
 * before we potentially clone/copy.
 */
if (icsk->icsk_ca_ops->flags & TCP_CONG_RTT_STAMP)
    __net_timestamp(skb); /*設定skb->tstamp,記錄傳送時間*/
 
static inline void __net_timestamp(struct sk_buff *skb)
{
    skb->tstamp = ktime_get_real(); /* 獲取當前時間的ktime_t表示 */
}

評價

我們知道當HZ < 1000時,計算得到的RTT的精確度就在1ms以上。這個時候可以通過設定

TCP_CONG_RTT_STAMP標誌來獲得更高精度的RTT,測量得到的RTT可以精確到微秒。

但是由於x86機器的HZ一般為1000,所以這個補丁的影響有限。

Author

zhangskd @ csdn blog