NET_DMA TCP在Linux中接收卸载

时间:2011-05-06 17:18:13

标签: performance linux-kernel tcp

Linux内核可以选择启用TCP接收副本卸载功能(CONFIG_NET_DMA)。我使用iperf(TCP窗口大小= 250 KB,缓冲区长度= 2 MB)和oprofile来测试三种情况下的性能:使用和不使用NET_DMA,NET_DMA启用和sk_rcvlowat设置为200 KB 。结果如下:

  • 禁用NET_DMA:带宽可达930 Mbps,__copy_tofrom_user占用cpu时间的36.1%。

  • 启用NET_DMA:带宽小于上述情况40 Mbps(890 Mbps),__copy_tofrom_user消耗33.5%的CPU时间。

  • 启用NET_DMA(sk_rcvlowat = 200KB):带宽为874 Mbps,__copy_tofrom_user占用cpu时间的25.1%。

我还尝试检查函数tcp_recvmsg()(在/net/ipv4/tcp.c中)(内核版本是2.6.32.2)。这是我理解NET_DMA工作方式的方式:

  

//在tcp_revmsg()

的开头
   target = sock_rcvlowat(sk, flags & MSG_WAITALL, len);
     

#ifdef CONFIG_NET_DMA

   tp->ucopy.dma_chan = NULL;

   preempt_disable();

   skb = skb_peek_tail(&sk->sk_receive_queue);

   {
           int available = 0;

           if (skb)
                   available = TCP_SKB_CB(skb)->seq + skb->len - (*seq);
           if ((available < target) &&
               (len > sysctl_tcp_dma_copybreak) && !(flags & MSG_PEEK) &&
               !sysctl_tcp_low_latency &&
               dma_find_channel(DMA_MEMCPY)) {
                   preempt_enable_no_resched();
                   tp->ucopy.pinned_list =
                                   dma_pin_iovec_pages(msg->msg_iov, len);
           } else {
                   preempt_enable_no_resched();
           }
   }
     

#ENDIF

len:是缓冲区长度,可以使用-l

中的iperf选项指定

target:是应返回的最小字节数tcp_recvmsg()。如果未设置sk->sk_rcvlowat,我看到该目标通常得到值1(在target = 1的情况下很少发生DMA传输。)

available:来自接收队列的第一个skb可用的字节数。

我认为条件(目标&lt; available)对于确定tcp_recvmsg()是否应该使用DMA至关重要。当我从I / OAT补丁文件中的注释中读取时,如果存在上下文切换使进程进入休眠状态并等待更多数据,则此条件为真。

  

//在tcp_recvmsg()

的while循环中      

if(复制&gt; =目标){

   /* Do not sleep, just process backlog. */

   release_sock(sk);

   lock_sock(sk);
     

}其他

   sk_wait_data(sk, &timeo);

当进程处于休眠状态时,到达的数据包将在tcp_dma_try_early_copy() tcp_rcv_established()/net/ipv4/tcp_input.c直接发送到用户空间缓冲区。也许这是NET_DMA的有效点,进程进入休眠状态,但数据可以通过硬件移动到其缓冲区。

  

//在/net/ipv4/tcp_input.c:tcp_dma_try_early_copy()

     

if((tp-> ucopy.len == 0)||

   (tcp_flag_word(tcp_hdr(skb)) & TCP_FLAG_PSH) ||

   (atomic_read(&sk->sk_rmem_alloc) > (sk->sk_rcvbuf >> 1))) {

       tp->ucopy.wakeup = 1;

       sk->sk_data_ready(sk, 0);
     

}

tcp_dma_try_early_copy()中的DMA处理将停止其作业,并在没有更多缓冲区(tp->ucopy.len == 0)或分配的skb的总大小大于1时唤醒休眠进程/ 2 sk_rcvbuf(我发现sk_rcvbuf设置为TCP窗口大小iperf)。

这是我第一次使用Linux中的TCP / IP堆栈。我不确定上面的结论是否正确,如果我错了请修理我。我的问题是:

Q1:为什么NET_DMA启用情况下的带宽总是低于没有NET_DMA的情况?

Q2:是否有一组很好的值(TCP窗口大小,缓冲区长度,sk_rcvlowat)来提升NET_DMA启用情况下的性能?

问题3:每次DMA传输仅约1448字节。它是否太小而不能被DMA化?

任何建议都表示赞赏。提前谢谢。

1 个答案:

答案 0 :(得分:2)

我的猜测是,对于小数据包(现在认为1448很小),激活和等待IOAT中断的延迟开销高于简单复制内存的开销,特别是当内存和CPU访问速度很快时。现代服务器可以使用memcpy推送5GB /秒。

对于10Gbit / sec以太网情况,尽可能使用更高的MTU并且肯定更大的缓冲区大小是值得的。我认为接收卸载的原始测试仅在单个数据包大约为PAGE_SIZE时开始显示性能提升。