linux 4.12内核busy poll分析

why busy poll

  • Interrupt Moderation 中断的间隔
  • Scheduling/Context Switching. 如ksoftirqd和应用程序的调度
  • Power Management 电源管理的方式,比如让CPU处在C0的最大工作状态
  • 每个队列一个cpu处理,避免资源竞争

可以说busy poll除了浪费cpu和电费外,对性能有很大的帮助。

在linux 3.11内核上已经有SO_BUSY_POLL socket选项可以开启busy poll.

根据文后的参考资料信息, 得到以下的性能数据。

mlx4驱动使用以下配置

1
2
rx-usecs: 16
rx-frames: 44

10G网卡,netperf使用TCP_RR保持连接(1 byte payload each way)
在3.11内核上:
正常模式下17500tps
busy poll模式下可以到63000tps
到4.11内核上可以到达77000tps

epoll busy poll

内核4.12增加了epoll的busy poll支持,使用这个功能基于一种假设,如果一个socket之前被napi处理,那么下一次也将被该napi处理。
因此如果该socket当前没有事件,则只用busy poll这个napi对应的网卡队列来处理数据包,直到有新的事件发生为止。
如果epoll中的sockets来源于不同的napi, 则在添加socket的时候,或者有epoll事件回调发生的时候重置epoll要busy poll的napi。

同时结合SO_INCOMING_CPU或者SO_REUSEPORT_ATTACH_C/EBPF选项, 使应用程序所在的cpu和协议栈所在的cpu一致,并启用系统busy poll,则epoll会在当前没有事件的时候(ready list为空), busy poll当前的napi。

下面以nginx为例来做个简单优化:
1.nginx使用reuseport, cpu亲和开启自动绑定
2.配置网卡队列,队列和nginx worker数量一致,通过rss/中断亲和/fdir设置队列和cpu的关联。
3.使用SO_REUSEPORT_ATTACH_EBPF选项设置reuseport算法返回数据包所在的cpu编号
4.开启busy poll模式, sysctl开启net_busy_poll

future work

应用程序sendmsg->…->qdisc enqueue/dequeue->驱动发送
调用路径太深了,尤其是对于实时要求高的应用程序,使用默认qdisc fifo算法在dequeue的时候,有可能一直在dequeue其他的应用程序的包。

因为增加cpu缓存热度,减少锁,提升多核的利用率等原因,通常会鼓励每个cpu一个对应的rx/tx队列,然后本地化处理数据包。
但是网卡使用过多的队列会降低napi的批处理能力。

Experts complain about enormous amount of cpu cycles spent in softirq handlers.
It has been shown that driving a 40Gbit NIC with small packets on 100,000 TCP sockets could consume 25 % of cpu
cycles on hosts with 44 queues with high tail latencies

同时由于L1,L2缓存通常较小,当所有cpu都被用于处理协议栈后,实际上cache会不断被内核代码和数据刷新,并没有提升cache利用率。
因此当cpu核心数越来越多的时候,应用使用部分cpu,这部分cpu可以绑定到对应的网卡队列,根据系统的真实负载来做busy polling, 同时留出其他核心用于内核和应用程序。

Eric Dumazet提出了一种实现, 根据NUMA创建cpu groups. 用group作为单位来进行配置和调度。
比如说一个64核心的机器,配置了16个队列作为网卡RSS, 然后中断绑定到对应0-15号cpu上(8个在numa node0上,8个在node1上)
并根据numa进行分组创建两个group。 这两个group根据系统的负载来确定busy polling的线程数量以及电源工作模式,同时group中线程的调度算法应该独立于其他应用程序有更高的优先级。
并尽量让这些内核线程中来处理qdisc的dequeue。

XDP/DPDK

这里还要简单介绍下XDP, XDP通过编写eBPF在进入协议栈前处理数据包,同时也支持poll的模式。
去年netdevconf演讲上,redhat的david miller强调了DPDK is not Linux, 但是同样的XDP is not DPDK。
XDP不是kernel bypass,更像是stack bypass。 编写eBPF为了安全考虑,本身功能就是受限的,因此相比起来目前还是DPDK在复杂场景下有更明显的优势。

这里有篇文章可以一读
xdp, well meaning but pointless

参考资料

Busy Polling: Past, Present, Future-Slide
Busy Polling: Past, Present, Future
linux 4.12 epoll add busy poll support