Chinaunix首页 | 论坛 | 博客
  • 博客访问: 226771
  • 博文数量: 17
  • 博客积分: 1545
  • 博客等级: 上尉
  • 技术积分: 302
  • 用 户 组: 普通用户
  • 注册时间: 2009-02-12 21:59
文章分类
文章存档

2011年(8)

2010年(5)

2009年(4)

分类: LINUX

2011-02-16 01:30:04

最近在把代码从18移植到 32的内核上,发现tcp_sacktag_write_queue函数改的面目全非,搞得我十分 头大,火大。
关于该函数的详细分析,请看http://simohayha.javaeye.com/blog/578744 ,我就不转载了。
比较大的变化有三个
1 tp->recv_sack_cache[]真正派上了用场,通过与上一次的sack块的比照,减少对发送缓存中的skb的查找次数。
对每个新sack块,比较是不是以前的sack块里面已经有了,如果已经有了,ok,可以直接退出来,如果没有顺序查找到,并将相应的发送包标记。如果新sack块的序号大于以前最大的那个sack块,那么直接跳到标记的最大的那个sack块。
如此,让我们假设一下重传包不丢,没有乱序的情况(这个是绝大多数的情况),对于sack包的处理,每次丢包是0(n),而在以前(我应该没记错)是o(kn),k=收到的sack包的数量。如果cwnd=1000,好吧,这个悲剧大了。
详细请看这一段的代码:
while (tcp_sack_cache_ok(tp, cache) &&
               !before(start_seq, cache->end_seq))
            cache++;

        /* Can skip some work by looking recv_sack_cache? */
        if (tcp_sack_cache_ok(tp, cache) && !dup_sack &&
            after(end_seq, cache->start_seq)) {

            /* Head todo? */
            if (before(start_seq, cache->start_seq)) {
                skb = tcp_sacktag_skip(skb, sk, &state,
                               start_seq);
                skb = tcp_sacktag_walk(skb, sk, next_dup,
                               &state,
                               start_seq,
                               cache->start_seq,
                               dup_sack);
            }

            /* Rest of the block already fully processed? */
            if (!after(end_seq, cache->end_seq))
                goto advance_sp;

            skb = tcp_maybe_skipping_dsack(skb, sk, next_dup,
                               &state,
                               cache->end_seq);

            /* ...tail remains todo... */
            if (tcp_highest_sack_seq(tp) == cache->end_seq) {
                /* ...but better entrypoint exists! */
                skb = tcp_highest_sack(sk);
                if (skb == NULL)
                    break;
                state.fack_count = tp->fackets_out;
                cache++;
                goto walk;
            }

            skb = tcp_sacktag_skip(skb, sk, &state, cache->end_seq);
            /* Check overlap against next cached too (past this one already) */
            cache++;
            continue;
        }

        if (!before(start_seq, tcp_highest_sack_seq(tp))) {
            skb = tcp_highest_sack(sk);
            if (skb == NULL)
                break;
            state.fack_count = tp->fackets_out;
        }

2 合并被确认的skb
新增加的函数tcp_shift_skb_data ,如此好处依然是提高效率,把相邻的包整合在一块,这样每次查找的数量就会更加减少(尤其是在重传丢包的时候),其查找次数和丢包的个数成正比,而不是与以前的(最坏情况下)和窗口成正比。

说到这,我可以来说一个我的亲身体会,如假包换,当时是拿TCP协议栈去和类FEC编码的算法去比,看谁的速度快。当时我们在300ms的rtt和10-20%的丢包率情况下,跑出了2MB的速度,但是,悲剧的发现,跑了10几个连接之后,一个CPU就耗完了。现在看来,如果我们是在32的内核上跑的话,性能应该会好很多。

3 重写了发现重传包丢失的函数
相比18内核(顺带说一下,有文献 已经证明18内核在发送重传包丢掉这个问题上是有bug的),这是一个很巧妙的算法,重传包以前,记住下一个要顺序发送的包(非重传包),如果这个包收到了,重传包还没有收到,那肯定就是丢掉了。

                                                                                                                   泓日天

阅读(3172) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2011-03-21 09:51:36

最近在哪工作呢?