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