[前言]
使用 DPDK 开发的朋友应该都了解使用 dpdk 的 fwd 线程的工作模式是 polling 模式, 即 100% 轮询的方式去加速网络 IO, 这样我们在操作系统层面上来观察目标 processer 会发现 usage 一直为 100%, 但是这真的是系统的真实负载么? 很显然并不是, 本文给出一种方法来计算 dpdk 的 fwd 线程的真实负载的方法.
[场景]
使用 DPDK 头痛的一点就是 DPDK 的 fwd 线程工作在 polling 模式, 会直接消耗一整个 processer 的计算资源, 有的时候为了性能考虑, 往往还会给当前 processer 设置 isolcpus, 将当前 processer 从内核的 CFS 调度器中 "剥离" 出来, 防止有其他的 task 被 "不长眼" 的 CFS 调度器调度到和 fwd 线程同一个 processer 上, 出现 context switch, 引起性能下降.
而工作在 polling 模式的 fwd 线程会出现非常蛋疼的一点就是面临 "无法有效的感知当前 processer 的压力" 的问题. 查看操作系统的相关信息, 会发现这个 processer 的 usage 一直处于 100%, 但是真实情况真的是这样么? 并不是, 在流量处于低谷的时候, 这个 processer 往往会出现空转的情况, 就是调用 dpdk 的 API 收包函数调 100 次, 次次收包个数都是 0, 因为根本就没有流量, 所以需要一种新的方法来计算使用 dpdk fwd 线程的负载情况.
额外多说一点, 为了防止 fwd 线程出现空转, 目前有不同种方法来 "尽量" 解决这种空转问题, 主流的通常有两种:
利用 sleep 函数, 简单粗暴, 结合内核的 NAPI 策略, 设定一个期望收包个数值, 当实际收包个数小于这个数值就判断当前流量不大, sleep 一下.
利用 dpdk 的 rsc 中断来解决, 由于 uio 驱动只有一个中断号, 因此这种方法在 uio 驱动基本没法用, 只能在 vfio 场景下用.
当然怎么防止 dpdk fwd 线程出现空转的解决方法不是这篇文章想讨论的主题, 我后续会写我个人的解决方案, 本篇文章更多的会聚焦在如何估算负载情况.
[分析]
- /* Receive Descriptor bit definitions */
- #define IXGBE_RXD_STAT_DD 0x01 /* Descriptor Done */
- #define IXGBE_RXD_STAT_EOP 0x02 /* End of Packet */
- #define IXGBE_RXD_STAT_FLM 0x04 /* FDir Match */
- #define IXGBE_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */
- uint32_t
- ixgbe_dev_rx_queue_count(struct rte_eth_dev *dev, uint16_t rx_queue_id)
- {
- #define IXGBE_RXQ_SCAN_INTERVAL 4
- volatile union ixgbe_adv_rx_desc *rxdp;
- struct ixgbe_rx_queue *rxq;
- uint32_t desc = 0;
- rxq = dev->data->rx_queues[rx_queue_id];
- rxdp = &(rxq->rx_ring[rxq->rx_tail]);
- while ((desc <rxq->nb_rx_desc) &&
- (rxdp->wb.upper.status_error &
- rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD))) {
- desc += IXGBE_RXQ_SCAN_INTERVAL;
- rxdp += IXGBE_RXQ_SCAN_INTERVAL;
- if (rxq->rx_tail + desc>= rxq->nb_rx_desc)
- rxdp = &(rxq->rx_ring[rxq->rx_tail +
- desc - rxq->nb_rx_desc]);
- }
- return desc;
- }
- if (fwd_rx_load>= 90 && rte_get_rx_queue_count()>= 512)
- // 需要采取措施, 流量很可能即将过载
来源: http://www.bubuko.com/infodetail-3379695.html