gpt4 book ai didi

performance - NET_DMA TCP 在 Linux 中接收卸载

转载 作者:可可西里 更新时间:2023-11-01 02:34:22 26 4
gpt4 key购买 nike

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

  • 禁用 NET_DMA:带宽可以达到 930 Mbps,__copy_tofrom_user消耗 36.1% 的 CPU 时间。

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

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

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

// at the start of 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 可用的字节数来自接收队列。

我认为条件 (target < available) 是决定是否 tcp_recvmsg() 的关键。是否应该使用 DMA。正如我从 I/OAT 补丁文件中的注释中读到的那样,当存在使进程休眠并等待更多数据的上下文切换时,此条件为真。

// in the while loop of tcp_recvmsg()

if (copied >= target) {

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

release_sock(sk);

lock_sock(sk);

} else

   sk_wait_data(sk, &timeo);

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

// in /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 时,将停止其工作并唤醒 sleep 进程大于 1/2 sk_rcvbuf (我发现 sk_rcvbuf 设置为 iperf 的 TCP 窗口大小)。

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

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

问题 2:是否有一组好的值(TCP 窗口大小、缓冲区长度、sk_rcvlowat)来提高启用 NET_DMA 情况下的性能?

Q3:每次DMA传输只有1448 Bytes左右。是否太小而无法进行 DMA 处理?

如有任何建议,我们将不胜感激。提前致谢。

最佳答案

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

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

关于performance - NET_DMA TCP 在 Linux 中接收卸载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5914829/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com