5 高带宽性能指南

Xillybus IP 核的用户常常进行数据带宽测试,以确保达到标称的数据传输速率。要实现这些目标,需要避免可能显著降低数据流速度的瓶 颈。

本节汇集了一系列指南,这些指南基于最常见的错误。遵循这些指南应能得到等于或略优于公布数据的带宽测量结果。

当然,在基于 Xillybus 的项目实现中遵循这些指南也很重要,以便项目充分利用 IP 核的全部能力。

问题通常在于主机处理数据的速度不够快: 数据速率测量不正确是抱怨无法达到公布数据的最常见原因。推荐 的方法是使用 Linux 的 “dd” 命令,如下文第 5.3 节所示。该工 具在 Xillybus 的 Windows 程序包中作为可执行文件提供。

对于一份“入门”指南而言,本节的信息相对高级。讨论中也引用了在其他文档中解释的高级主题。尽管如此,仍在本指南中 给出这些指南,因为许多用户会在熟悉 IP 核的早期阶段进行性能测试。

5.1 不要使用环回

在 demo bundle(FPGA 内部)中,两对流之间有一个环回(loopback)。这使得 “Hello, world” 测试成为可能(见第 3 节),但这不利于测试 性能。

问题在于 Xillybus IP 核会以数据突发传输的方式非常快速地填满 FPGA 内部的 FIFO。由于这个 FIFO 变满(full),数据流 会瞬间停止。

环回正是通过这个 FIFO 实现的,因此该 FIFO 的两端都连接到了 IP 核。当 FIFO 中有数据时,IP 核会从 FIFO 中取出该数 据并将其发送回主机。这也发生得非常快,因此 FIFO 变空(empty)。又一次,数据流瞬间停止。

由于数据流中这些瞬间暂停,测得的数据传输速率低于预期。这是因为 FIFO 太浅,并且 IP 核同时负责填充和清空 FIFO。

在实际场景中没有环回。相反,在 FIFO 的另一端有应用逻辑。考虑达到最大数据传输速率的使用场景: 在此 场景中,应用逻辑消耗 FIFO 中数据的速度与 IP 核填充该 FIFO 的速度一样快。因此 FIFO 永远不会满。

同样,对于相反方向: 应用逻辑填充 FIFO 的速度与 IP 核消耗数据的速度一样快。因此 FIFO 永远不会 空。

从功能角度来看,FIFO 偶尔变满或变空没有问题。这仅仅会导致数据流短暂停顿。一切都能正常工作,只是无法以最大速 度运行。

可以轻松修改 demo bundle 以进行性能测试: 例如,要测试 \\.\xillybus_read_32,将 user_r_read_32_empty 与 FPGA 内部的 FIFO 断开。而是将该信号连接到常量零。结 果,IP 核将认为 FIFO 永远不会空。因此数据传输将以最大速度进行。

这意味着 IP 核偶尔会从空的 FIFO 读取。因此,到达主机的数据并不总是有效的(由于下溢(underflow))。但就速度测 试而言,这无关紧要。如果数据内容很重要,一个可能的解决方案是让应用逻辑尽可能快地填充 FIFO(例如,使用计数器的输出)。

同样,测试 \\.\xillybus_write_32: 将 user_w_write_32_full 与 FIFO 断开,并 将该信号连接到常量零。IP 核将认为 FIFO 永远不会满,因此数据传输以最大速度进行。由于上溢(overflow),发送到 FIFO 的数据将部分 丢失。

注意,断开环回允许分别测试每个方向。然而,这也是同时测试两个方向的正确方法。

5.2 不要涉及磁盘或其他存储

磁盘、固态硬盘和其他类型的计算机存储常常是带宽预期无法达到的原因。高估存储介质的速度是一个常见错误。

操作系统的缓存机制增加了混淆: 当数据写入磁盘时,并不总是涉及物理存储介质。相反,数据写入 RAM,稍 后才写入磁盘本身。从磁盘读取操作也可能不涉及物理介质,当最近已经读取过相同的数据时就会发生这种情况。

在现代计算机上,缓存可能非常大。因此,在磁盘的真实速度限制变得可见之前,可以流动数吉字节的数据。这常常导致用 户认为 Xillybus 数据传输有问题: 对于数据传输速率的这种突然变化,没有其他解释。

对于固态硬盘(闪存),还有一个额外的混淆来源,特别是在长时间连续写入操作期间: 在闪存驱动的底层实 现中,必须擦除未使用的内存段(块)以准备写入闪存。这是因为数据只能写入已擦除的块。

开始时,闪存驱动通常有很多已经擦除的块。这使得写操作很快: 有很多空间可以写入数据。然而,当没有更 多已擦除的块时,闪存驱动被迫擦除块并可能执行数据碎片整理。这可能导致显著的、无明显原因的减速。

由于这些原因,测试 Xillybus 带宽时绝不应涉及任何存储介质。即使存储介质在短时间测试中看起来足够快,这也可能具有 误导性。

一个常见的错误是通过测量将数据从 Xillybus 设备文件复制到磁盘上大文件所需的时间来估算性能。尽管此操作在功能上是 正确的,但用这种方式测量性能可能完全错误。

如果存储旨在作为应用程序的一部分(例如数据采集(data acquisition)),建议彻底测试该存储介质: 应对 存储介质进行广泛、长期的测试,以验证其是否满足预期。短暂的基准测试可能极具误导性。

5.3 读取和写入大块数据

每次调用 _read() 和 _write() 函数都会导致对操作系统的一次系统调用(system call)。因此,执行这些函数调用需要大量 的 CPU 周期。因此,确保缓冲区大小足够大以减少系统调用次数非常重要。这对于带宽测试和高性能应用程序都是如此。

通常,每次函数调用的缓冲区大小以 128 kB 为宜。这意味着每次这样的函数调用最多传输 128 kB。然而,这些函数调用允 许传输较少的数据。

需要注意的是,第 4.13.3 节中提到的示例程序 (streamread 和 streamwrite)不适合用于测量性能: 这些程序中的缓冲区大小为 128 字节(而非 kB)。这简化了示例,但使 得程序对于性能测试来说太慢。

以下 shell 命令可在 Cygwin 内用于快速速度检查(根据需要替换 \\\\.\\xillybus\_* 名 称):

dd if=/dev/zero of=\\\\.\\xillybus_sink bs=128k
dd if=\\\\.\\xillybus_source of=/dev/null bs=128k

这些命令会一直运行,直到用 CTRL-C 停止。添加 “count=” 以测试固定数据量。

更多关于使用 Cygwin 进行测试的信息,请参阅第 4.3 节。

5.4 注意 CPU 消耗

在高数据速率的应用中,瓶颈通常是计算机程序,而不一定是数据传输。

高估 CPU 的能力是一个常见错误。与普遍看法相反,当数据速率超过 100-200 MB/s 时,即使是最快的 CPU 也难以对数据 进行有意义的处理。可以通过多线程提高性能,但令人惊讶的是,这可能被认为是必要的。

有时,缓冲区大小不合适(如上所述)也会导致过度的 CPU 消耗。

因此,密切关注 CPU 消耗非常重要。例如,可以使用任务管理器(Task Manager)来实现这一目的。然而,该程序显示的 信息在多核处理器计算机(即现今几乎所有计算机)上可能具有误导性。例如,如果有四个处理器核心,25% 的 CPU 使用率意味着什么?是 CPU 消耗低,还是在某个特定线程上达到了 100%?不同的系统监控工具以不同方式显示此信息。

5.5 不要让读取和写入相互依赖

当需要双向通信时,一个常见的错误是编写只有一个线程的计算机程序。该程序通常有一个循环,同时执行读取和写 入: 每次迭代,向 FPGA 写入数据,然后从相反方向读取数据。

有时这种程序没有问题,例如两个流在功能上独立。然而,这种程序的意图通常是让 FPGA 执行协处理。这种编程风格基于 一种误解,即程序应该发送一部分数据进行处理,然后读回结果。因此,每次迭代构成了每个数据块的处理。

这种方法不仅效率低下,而且程序常常会卡住。Xillybus Windows 主机应用程序编程指南的第 6.5 节详细阐述了此主题,并提出了更合适的编程技术。

5.6 了解主机 RAM 的限制

这主要与使用 revision XL / XXL IP 核相关: 主板(或嵌入式处理器)与 DDR RAM 之间的数据带宽是有限的。 在计算机的常规使用中,这种限制很少被注意到。但对于使用 Xillybus 的非常苛刻的应用,这个限制可能成为瓶颈。

请记住,每次将数据从 FPGA 传输到用户空间程序需要对 RAM 进行两次操作: 第一次操作是 FPGA 将数据写 入 DMA 缓冲区。第二次操作是驱动程序将数据复制到用户空间程序可访问的缓冲区。出于类似原因,当数据向相反方向传输时,也需要对 RAM 进行两次操作。

DMA 缓冲区和用户空间缓冲区之间的分离是操作系统要求的。所有使用 _read() 和 _write()(或类似函数调用)的 I/O 都必须以这种方式 进行。

例如,对 XL IP 核进行测试,预计每个方向达到 3.5 GB/s,即总计 7 GB/s。然而,RAM 的访问次数翻倍。因此 RAM 的带 宽需求为 14 GB/s。并非所有主板都具备此能力。同时还要记住,主机同时将 RAM 用于其他任务。

对于 revision XXL,由于相同原因,即使是单个方向的简单测试也可能超过 RAM 的带宽能力。

5.7 足够大的 DMA 缓冲区

这很少成为问题,但仍值得一提: 如果主机上为 DMA 缓冲区分配的 RAM 太少,可能会降低数据传输速度。原 因是主机被迫将数据流分成小段。这会导致 CPU 周期浪费。

所有 demo bundle 都分配了足够的 DMA 内存用于性能测试。在 IP Core Factory 正确生成的 IP 核也是如此: “Autoset Internals” 已启用,并且 “Expected BW” 反映了所需的数据带宽。“Buffering” 应选择 10 ms,尽管任何选项很可能都没问题。

总的来说,这对于带宽测试已经足够: 至少四个 DMA 缓冲区,其总 RAM 量对应于 10 ms 内的数据传输。当 然,必须考虑所需的数据传输速率。

5.8 使用正确的数据字宽度

很明显,在 FPGA 内部,每个时钟周期,应用逻辑只能向 IP 核传输一个字的数据。因此,数据字宽度和 bus_clk 的频率限 制了数据传输速率。

除此之外,默认修订版(revision A IP 核)还有相关的限制: 当字宽度为 8 位或 16 位时,PCIe 能力的利用效 率不如字宽度为 32 位时高。因此,需要高性能的应用和测试应仅使用 32 位。这不适用于 revision B 及更高版本的 IP 核。

从 revision B 开始,字宽度最高可达 256 位。字宽度应至少与 PCIe 块的宽度相同。因此,对于数据带宽测试,需要以下数 据字宽度:

  • 默认修订版(Revision A): 32 位。

  • Revision B: 至少 64 位。

  • Revision XL: 至少 128 位。

  • Revision XXL: 256 位。

如果数据字宽度大于上述要求(如果可能),通常可以获得稍好一些的结果。原因是应用逻辑与 IP 核之间的数据传输得到了 改善。

5.9 参数调优

demo bundle 中的 PCIe 块参数是为了支持标称数据传输速率而选择的。性能是在配备 x86 系列 CPU 的典型计算机上测试的。

此外,在 IP Core Factory 生成的 IP 核通常不需要任何微调: 当启用 “Autoset Internals” 时,流可能会在性能 与 FPGA 资源利用率之间取得最佳平衡。因此,每个流都能保证所需的数据传输速率。

因此,尝试微调 PCIe 块或 IP 核的参数几乎总是毫无意义的。对于默认修订版(revision A)的 IP 核,这种调优总是毫无意 义。如果这种调优提高了性能,那么问题很可能出在应用逻辑或用户应用软件中的缺陷。在这种情况下,纠正这个缺陷可以获得更多收 益。

然而,在需要卓越性能的罕见场景中,可能有必要略微调优 PCIe 块的参数以达到所需的数据速率。这对于从主机到 FPGA 的流尤其相关。自定义 Xillybus IP 核指南 的第 4.5 节讨论了如何进行这种调优。

注意,即使这种微调有益,修改的也不是 Xillybus IP 核的参数。只调整 PCIe 块。一个常见的错误是试图通过调优 IP 核的参 数来提高数据传输速率。相反,问题几乎总是本章前面提到的某个问题。