1 如何使用DPDK和GPUdev增强内联数据包处理-德赢Vwin官网 网
0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何使用DPDK和GPUdev增强内联数据包处理

星星科技指导员 来源:NVIDIA 作者:Elena Agostini 2022-05-07 10:08 次阅读

使用 GPU网络数据包进行内联处理是一种数据包分析技术,可用于许多不同的应用领域:信号处理、网络安全、信息收集、输入重建等。

这些应用程序类型的主要要求是尽快将接收到的数据包移动到 GPU 内存中,以触发负责对其执行并行处理的 CUDA 内核。

总体思路是创建一个连续的异步管道,能够将数据包从网卡直接接收到 GPU 内存中。您还可以使用 CUDA 内核来处理传入的数据包,而无需同步 GPU 和 CPU

有效的应用程序工作流包括使用无锁通信机制在以下播放器组件之间创建一个协调的连续异步管道:

network controller 向 GPU 内存提供接收到的网络数据包

CPU 用于查询网络控制器以获取有关接收到的数据包的信息

GPU 用于接收数据包信息并直接将其处理到 GPU 内存中

图 1 显示了使用 NVIDIA GPU 和 ConnectX 网卡的加速内联数据包处理应用程序的典型数据包工作流场景。

pYYBAGJ11JuAJW5fAAF34hR_9EE757.png

图 1 。典型的内联数据包处理工作流场景

在这种情况下,避免延迟是至关重要的。不同组件之间的通信越优化,系统的响应速度就越快,吞吐量也就越高。每一步都必须在所需资源可用时以内联方式进行,而不会阻塞任何其他等待的组件。

您可以清楚地识别两种不同的流:

Data flow :通过 PCIe 总线在网卡和 GPU 之间交换优化的数据(网络数据包)。

Control flow : CPU 协调 GPU 和网卡。

数据流

关键是优化网络控制器和 GPU 之间的数据移动(发送或接收数据包)。它可以通过 GPUDirect RDMA 技术实现,该技术使用 PCI Express 总线接口的标准功能,在 NVIDIA GPU 和第三方对等设备(如网卡)之间实现直接数据路径。

GPUDirect RDMA 依赖于 NVIDIA GPU 在 PCI Express 基址寄存器( BAR )区域上公开部分设备内存的能力。有关更多信息,请参阅 CUDA 工具包文档中的 使用 GPUDirect-RDMA 开发 Linux 内核模块 。 在现代服务器平台上对 GPUDirect-RDMA 进行基准测试 文章对使用不同系统拓扑的标准 IB 谓词执行网络操作(发送和接收)时的 GPUDirect RDMA 带宽和延迟进行了更深入的分析。

poYBAGJ11J2AdZNTAAGq0tsSGxA199.png

图 2 。 NVIDIA GPUDirect RDMA 使用 PCI Express 的标准功能,为 GPU 和第三方对等设备之间的数据交换提供了直接路径

要在 Linux 系统上启用 GPUDirect RDMA ,需要 nvidia-peermem 模块(在 CUDA 11.4 及更高版本中提供)。图 3 显示了最大化 GPUDirect RDMA 内部吞吐量的理想系统拓扑:在 GPU 和 NIC 之间使用专用 PCIe 交换机,而不是通过与其他组件共享的系统 PCIe 连接。

poYBAGJ11J-AI7eYAAED6LJLG_k257.png

图 3 。理想的拓扑结构,最大限度地提高网络控制器和 GPU 之间的内部数据吞吐量

控制流

CPU 是网络控制器和 GPU 之间协调和同步活动的主要参与者,用于唤醒 NIC ,将数据包接收到 GPU 内存中,并通知 CUDA 工作负载有新数据包可供处理。

在处理 GPU 时,强调 CPU 和 GPU 之间的异步非常重要。例如,假设一个简单的应用程序在主循环中执行以下三个步骤:

接收数据包。

处理数据包。

发回修改过的数据包。

在本文中,我将介绍在这种应用程序中实现控制流的四种不同方法,包括优缺点。

方法 1

图 4 显示了最简单但最不有效的方法:单个 CPU 线程负责接收数据包,启动 CUDA 内核来处理它们,等待 CUDA 内核完成,并将修改后的数据包发送回网络控制器。

poYBAGJ11J-ACqN1AADDCJkvql0225.png

图 4 。单个 CPU 将数据包传递到 CUDA 内核并等待完成以执行下一步的工作流

如果数据包处理不是那么密集,那么这种方法的性能可能会比只使用 CPU 处理数据包而不使用 GPU 更差。例如,您可能具有高度的并行性来解决数据包上的一个困难且耗时的算法

方法 2

在这种方法中,应用程序将 CPU 工作负载分成两个 CPU 线程:一个用于接收数据包并启动 GPU 处理,另一个用于等待 GPU 处理完成并通过网络传输修改后的数据包(图 5 )。

poYBAGJ11KGAMYqIAAFF1L7iu6Y387.png

图 5 。拆分 CPU 线程以通过 GPU 处理数据包

这种方法的一个缺点是,每次累积数据包的突发都会启动一个新的 CUDA 内核。 CPU 必须为每次迭代支付 CUDA 内核启动延迟。如果 GPU 被淹没,数据包处理可能不会立即执行,从而导致延迟。

方法 3

图 6 显示了第三种方法,它涉及使用 CUDA 持久内核。

Inline-Packet-Fig-6.png

图 6 。使用持久 CUDA 内核进行内联数据包处理。

CUDA 持久内核是一个预启动的内核,它正忙着等待来自 CPU 的通知:新数据包已经到达并准备好进行处理。当数据包准备好后,内核通知第二个 CPU 线程它可以向前发送数据包。

实现此通知系统的最简单方法是使用忙等待标志更新机制在 CPU 和 GPU 之间共享一些内存。虽然 GPUDirect RDMA 旨在从第三方设备直接访问 GPU 内存,但您可以使用这些 API 创建 GPU 内存的完全有效的 CPU 映射。 CPU 驱动的拷贝的优点是所涉及的开销小。现在可以通过 GDRCopy 库启用此功能。

直接映射 GPU 内存进行信令,可以从 CPU 修改内存,并在轮询期间降低 GPU 的延迟成本。您也可以将该标志放在从 GPU 可见的 CPU 固定内存中,但 CUDA 内核轮询 CPU 内存标志将消耗更多 PCIe 带宽并增加总体延迟。

这种快速解决方案的问题在于它有风险,而且 CUDA 编程模型不支持它。 GPU 内核不能被抢占。如果写得不正确,持久内核可能会永远循环。此外,长期运行的持久内核可能会失去与其他 CUDA 内核、 CPU 活动、内存分配状态等的同步。

它还拥有 GPU 资源(例如,流式多处理器),如果 GPU 真的忙于其他任务,这可能不是最好的选择。如果您使用 CUDA 持久内核,那么您的应用程序必须具有良好的处理能力。

方法 4

最后一种方法是前两种方法的混合解决方案:使用 CUDA 流内存操作 要等待或更新通知标志,请在 CUDA 流上预启动一个 CUDA 内核,每接收一组数据包。

pYYBAGJ11KuAXhbyAAGWfudvy_4390.png

图 7 。使用模型组合的内联数据包处理的混合方法

这种方法的不同之处在于 GPU HW (使用cuStreamWaitValue)轮询内存标志,而不是阻塞 GPU 流式多处理器,并且只有在数据包准备就绪时才会触发数据包的处理内核。

类似地,当处理内核结束时,cuStreamWriteValue通知负责发送数据包的 CPU 线程数据包已被处理。

这种方法的缺点是,应用程序必须不时地用cuStreamWriteValue+cuStreamWaitValue内核+ CUDA 的新序列重新填充 GPU ,以避免在空流没有准备好处理更多数据包的情况下浪费执行时间。这里的 CUDA 图是在流上重新发布的好方法。

不同的方法适用于不同的应用程序模式。

DPDK 和 GPUdev

数据平面开发工具包 ( DPDK )是一组库,用于帮助加速在各种 CPU 体系结构和不同设备上运行的数据包处理工作负载。

在 DPDK 21.11 中, NVIDIA 引入了一个名为 GPUdev 的新库,以在 DPDK 的上下文中引入 GPU 的概念,并增强 CPU 、网卡和 GPU 之间的对话。 GPUdev 在 DPDK 22.03 中扩展了更多功能。

图书馆的目标如下:

介绍从 DPDK 通用库管理的 GPU 设备的概念。

实现基本的 GPU 内存交互,隐藏特定于 GPU 的实现细节。

减少网卡、 GPU 设备和 CPU 之间的间隙,增强通信。

将 DPDK 集成简化为 GPU 应用程序。

通过通用层公开 GPU 特定于驱动程序的功能。

对于特定于 NVIDIA 的 GPU , GPUdev 库功能通过 CUDA 驱动程序 DPDK 库 。要为 NVIDIA GPU 启用所有gpudev可用功能, DPDK 必须构建在具有 CUDA 库和 GDRCopy 的系统上。

有了这个新库提供的功能,您可以轻松地通过 GPU 实现内联数据包处理,同时处理数据流和控制流。

DPDK 在 mempool 中接收数据包,这是一个连续的内存块。通过以下指令序列,您可以启用 GPUDirect RDMA 在 GPU 内存中分配 mempool ,并将其注册到设备网络中。

struct rte_pktmbuf_extmem gpu_mem; gpu_mem.buf_ptr = rte_gpu_mem_alloc(gpu_id, gpu_mem.buf_len, alignment)); /* Make the GPU memory visible to DPDK */ rte_extmem_register(gpu_mem.buf_ptr, gpu_mem.buf_len, NULL, gpu_mem.buf_iova, NV_GPU_PAGE_SIZE); /* Create DMA mappings on the NIC */ rte_dev_dma_map(rte_eth_devices[PORT_ID].device, gpu_mem.buf_ptr, gpu_mem.buf_iova, gpu_mem.buf_len)); /* Create the actual mempool */ struct rte_mempool *mpool = rte_pktmbuf_pool_create_extbuf(... , &gpu_mem, ...);

图 8 显示了 mempool 的结构:

图 8 用于内联数据包处理的 mempool 结构

对于控制流,要启用 CPU 和 GPU 之间的通知机制,可以使用gpudev通信列表:在 CPU 内存和 CUDA 内核之间的共享内存结构。列表中的每一项都可以保存接收到的数据包的地址(mbufs),以及一个用于更新处理该项状态的标志(数据包就绪、处理完成等)。

struct rte_gpu_comm_list { /** DPDK GPU ID that will use the communication list. */ uint16_t dev_id; /** List of mbufs populated by the CPU with a set of mbufs. */ struct rte_mbuf **mbufs; /** List of packets populated by the CPU with a set of mbufs info. */ struct rte_gpu_comm_pkt *pkt_list; /** Number of packets in the list. */ uint32_t num_pkts; /** Status of the packets’ list. CPU pointer. */ enum rte_gpu_comm_list_status *status_h; /** Status of the packets’ list. GPU pointer. */ enum rte_gpu_comm_list_status *status_d;
};

伪代码示例:

struct rte_mbuf * rx_mbufs[MAX_MBUFS]; int item_index = 0; struct rte_gpu_comm_list *comm_list = rte_gpu_comm_create_list(gpu_id, NUM_ITEMS); while(exit_condition) { ... // Receive and accumulate enough packets nb_rx += rte_eth_rx_burst(port_id, queue_id, &(rx_mbufs[0]), rx_pkts); // Populate next item in the communication list. rte_gpu_comm_populate_list_pkts(&(p_v->comm_list[index]), rx_mbufs, nb_rx); ... index++; }

为简单起见,假设应用程序遵循 CUDA 持久内核场景, CUDA 内核上的轮询端看起来类似于以下代码示例:

__global__ void cuda_persistent_kernel(struct rte_gpu_comm_list *comm_list, int comm_list_entries) { int item_index = 0; uint32_t wait_status; /* GPU kernel keeps checking exit condition as it can’t be preempted. */ while (!exit_condition()) { wait_status = RTE_GPU_VOLATILE(comm_list[item_index].status_d[0]); if (wait_status != RTE_GPU_COMM_LIST_READY) continue; if (threadIdx.x < comm_list[item_index]->num_pkts) { /* Each CUDA thread processes a different packet. */ packet_processing(comm_list[item_index]->addr, comm_list[item_index]->size, ..); } __syncthreads(); /* Notify packets in the items have been processed */ if (threadIdx.x == 0) { RTE_GPU_VOLATILE(comm_list[item_index].status_d[0]) = RTE_GPU_COMM_LIST_DONE; __threadfence_system(); } /* Wait for new packets on the next communication list entry. */ item_index = (item_index+1) % comm_list_entries; } }

图 9 持久内核中轮询端伪代码的工作流示例

NVIDIA 使用 DPDK gpudev库进行内联数据包处理的一个具体用例位于 空中应用框架 中,用于构建高性能、软件定义的 5G 应用程序。在这种情况下,必须在 GPU 内存中接收数据包,并根据 5G 特定的数据包头重新排序,这样可以在重新排序的有效负载上开始信号处理。

图 10 使用 DPDK 的内联数据包处理用例 gpudev 在空中 5G 软件中

l2fwd nv 应用程序

为了提供如何实现内联数据包处理和使用 DPDK gpudev库的实际示例,l2fwd-nv示例代码已在 /NVIDIA/l2fwd-nv GitHub repo 上发布。这是使用 GPU 功能增强的普通 DPDK l2fwd示例的扩展。应用程序布局是接收数据包,交换每个数据包的 MAC 地址(源和目的地),并传输修改后的数据包。

L2fwd-nv为本文讨论的所有方法提供了一个实现示例,以供比较:

CPU 仅限

CUDA 每组数据包的内核数

CUDA 持久内核

CUDA 图

例如,图 11 显示了带有 DPDK gpudev对象的 CUDA 持久内核的时间线。

图 11 使用 DPDK 的 CUDA 持久内核的时间线示例gpudev objects

为了测量l2fwd-nv相对于 DPDK testpmd数据包生成器的性能,图 12 中使用了两个与 CPU 背靠背连接的千兆字节服务器: Intel Xeon Gold 6240R 、 PCIe gen3 专用交换机、 Ubuntu 20.04 、 MOFED 5.4 和 CUDA 11.4 。

图 12 测试 l2fwd nv 性能的两个千兆字节服务器配置

图 13 显示,当为数据包使用 CPU 或 GPU 内存时,峰值 I / O 吞吐量是相同的,因此使用其中一个不会带来固有的损失。这里的数据包被转发而不被修改。

图 13 峰值 I / O 吞吐量是相同的

为了突出不同 GPU 数据包处理方法之间的差异,图 14 显示了方法 2 ( CUDA 内核/数据包集)和方法 3 ( CUDA 持久内核)之间的吞吐量比较。这两种方法都将数据包大小保持在 1024 字节,在触发 GPU 工作以交换数据包的 MAC 地址之前,改变累积数据包的数量。

图 14 GPU 数据包处理方法之间的差异

对于这两种方法,每次迭代 16 个数据包会导致控制平面中的交互过多,并且无法达到峰值吞吐量。由于每次迭代 32 个数据包,持久化内核可以跟上峰值吞吐量,而每次迭代的单个启动仍然有太多的控制平面开销。对于每次迭代 64 和 128 个数据包,这两种方法都能够达到峰值 I / O 吞吐量。这里的吞吐量测量不是零丢失数据包。

结论

在本文中,我讨论了使用 GPU 优化内联数据包处理的几种方法。根据应用程序的需要,您可以应用多个工作流模型,以减少延迟,从而提高性能。 DPDK gpudev 库还有助于简化您的编码工作,以在最短的时间内获得最佳结果。

其他需要考虑的因素,取决于应用程序,包括在触发数据包处理之前,在接收端积累足够的数据包需要花费多少时间,有多少线程可用于尽可能多地增强不同任务之间的并行性,以及内核在执行中应该持续多长时间。

关于作者

Elena Agostini与意大利国家研究委员会( National Research Council of Italy )合作,获得了罗马大学( University of Rome “ La Sapienza ”)计算机科学与工程博士学位。她目前是 NVIDIA 的高级软件工程师。她的研究兴趣包括高性能互连、 GPUDirect 技术、网络协议、快速数据包处理和 DOCA 。 Elena 目前的重点是应用于 Aeror 的 NVIDA GPUDirect 技术,这是一组 SDK ,可实现 GPU 加速、软件定义的 5G 无线 RAN 。她也是 DPDK 的撰稿人。

审核编辑:郭婷

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表德赢Vwin官网 网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • NVIDIA
    +关注

    关注

    14

    文章

    4978

    浏览量

    102982
  • gpu
    gpu
    +关注

    关注

    28

    文章

    4729

    浏览量

    128887
  • CUDA
    +关注

    关注

    0

    文章

    121

    浏览量

    13620
收藏 人收藏

    评论

    相关推荐

    mtu配置步骤详解 mtu与数据包丢失的关系

    MTU(Maximum Transmission Unit)即最大传输单元,是指一种通信协议的某一层上面所能通过的最大数据报大小,单位是字节。MTU配置步骤及其与数据包丢失的关系如下: MTU配置
    的头像 发表于 12-16 14:33 325次阅读

    艾体宝干货 OIDA之四:掌握数据包分析-分析的艺术

    本文是OIDA方法系列的最后一部分,重点介绍了数据包分析的“分析”阶段。这一最后阶段将剖析阶段的精炼数据转化为可操作的见解,使网络管理员和安全专业人员能够解决问题、优化性能并增强安全性。分析是实现
    的头像 发表于 09-24 11:47 190次阅读
    艾体宝干货 OIDA之四:掌握<b class='flag-5'>数据包</b>分析-分析的艺术

    请问DCTCP与DCUDP 的登录数据包和心跳数据包与服务器端是如何交互的?

    DCTCP与DCUDP的登录数据包和心跳数据包与服务器端是如何交互的?
    发表于 07-25 06:37

    esp8266怎么做才能每秒发送更多的数据包呢?

    数据包的速度,即每秒大约 50 个 UDP 数据包。高波特率唯一改变的是,在数据包较大的情况下,我可以以与轻量级数据包相同的速度发送数据包
    发表于 07-22 08:00

    使用AT SAVETRANSLINK时UDP数据包丢失怎么解决?

    Android 发送一个小 UDP 数据包(5 字节)。这个小数据包被我的微控制器在UART上接收到。微控制器将更大的数据包(可变长度,约 100 字节)发送回 UART。ESP在UART上接
    发表于 07-18 07:17

    能否在ESP结束之前通过串行端口停止传入的UDP数据包的传输以解析下一个UDP数据包

    丢弃在ESP完成之前不需要的数据包,以便通过串行端口发送它以接收下一个数据包, 如果没有,我必须按顺序读取所有传入的数据包,需要的和不需要的, 而且波特率不足,主机处理器开销大, 我
    发表于 07-16 06:18

    如何直接从phy mac层发送和接收802.11数据包

    我阅读了完整的文档(espressif_iot_esp8266ex_development_kit_v0.9.4.zip),但我没有找到答案: 是否可以访问 802.11 数据包,并通过应用程序处理它们? 我希望能够直接从 phy mac 层发送和接收 802.11
    发表于 07-15 08:03

    请问如何使用AT CIPSEND或AT CIPSENDBUF发送多个数据包

    我可以使用 AT CIPSEND 发送单个数据包。但是我必须发送一系列二进制数据包。如何使用AT CISEND或AT CIPSENDBUF发送多个数据包,什么是正确的算法? 到目前为止,我尝试
    发表于 07-15 07:37

    在AN65974中短数据包和零长数据包是什么意思?

    在 AN65974 中,短数据包和零长数据包是什么意思? 非常感谢!
    发表于 05-30 07:41

    如何在AIROC GUI上获取良好数据包和总数据包

    使用 IQxel-MW LifePoint 作为发生器并发送波形BT_1DH5_00001111_Fs80M.iqvsg,但无法在 AIROC 工具中接收数据包。 以下是从 IQxel 发送
    发表于 05-22 06:39

    请问高端网络芯片如何处理数据包呢?

    随着网络芯片带宽的持续提升,其内部数据包处理单元的工作负载也随之增加。然而,如果处理单元无法与网络接口的传入速率相匹配,将无法及时处理数据包
    的头像 发表于 04-02 16:36 621次阅读
    请问高端网络芯片如何<b class='flag-5'>处理</b><b class='flag-5'>数据包</b>呢?

    联数据栈网关是什么?

    。 物联数据栈网关在物理层面上可以通过不同的通信协议与物联网设备进行通信,可以与多个物联网设备建立连接,同时处理多个设备的数据。 物联数据栈网关可以支持不同的物联网设备使用的不同协议,
    的头像 发表于 03-29 17:10 308次阅读

    STM32H7接收数据包异常,一接收的数据出现两发送的内容怎么解决?

    节:be1c0101属于发送数据包1的; 剩余其他字节:属于发送数据包2的; 问题困扰很久了,请大家帮忙处理下,急急急!
    发表于 03-08 08:05

    DPDK在AI驱动的高效数据包处理应用

    传统的数据包处理方式是数据包先到内核最后再到用户层进行处理。这种方式会增加额外的延迟和CPU开销,严重影响数据包
    的头像 发表于 02-25 11:28 931次阅读
    <b class='flag-5'>DPDK</b>在AI驱动的高效<b class='flag-5'>数据包</b><b class='flag-5'>处理</b>应用

    使用P4和Vivado工具简化数据包处理设计

    德赢Vwin官网 网站提供《使用P4和Vivado工具简化数据包处理设计.pdf》资料免费下载
    发表于 01-26 17:49 0次下载
    使用P4和Vivado工具简化<b class='flag-5'>数据包</b><b class='flag-5'>处理</b>设计