首页 > 文章 > Zynq UltraScale+ MPSOC 上的存储性能开发工具套件 (SPDK)

Zynq UltraScale+ MPSOC 上的存储性能开发工具套件 (SPDK)

John Linn 2020年01月13日

简介

NVMe 存储器件是您系统中的瓶颈吗?也许存储性能开发工具套件(SPDK) 是您通过关注您的 NVMe 存储性能来提高整体系统性能的下一步选择。

SPDK 是一个面向 Linux 用户空间设计的开源项目。SDPK 使用数据平面开发工具套件(DPDK)。SPDK 在成为开源项目之前是 Intel 项目,因此 X86平台是其主要平台。

您对 SDPK 感兴趣可能有两个原因。第一个也是最明显的原因是为了性能。第二个原因可能是需要一个比 Linux 内核许可证更宽松的许可证。

以下段落描述了在赛灵思 ZCU106 电路板上使用的带 MPSOC 的 SPDK 的原型系统。ZCU106 平台是使用 SSD 作为 NVMe PCIe 端点的 PCIe 根联合体。实现基本功能是该原型的唯一目标。

期望

本文档不是针对任何特定元素(如 Linux 或 PetaLinux)设计的教程,而是旨在帮助简化原型制作流程。本文档并不打算一步一步地介绍每个命令,而是想要像实验笔记本描述那样。


测试环境

赛灵思 2019.1 版用于所有使用赛灵思工具的构建。

X86 平台

64 位 X86 PC 用于 SPDK 的早期测试,因为使用与嵌入式平台相同的 NVMe SSD 可以快速验证构建和测试流程。SPDK 文档对于这一早期测试很有用。SPDK 可轻松地在 X86 PC 上进行本地构建,从而加快原型制作流程。

嵌入式平台

赛灵思 ZCU106 电路板被设计成端点,因为它有边缘连接器。对于该原型,ZCU106 电路板与用于 FMC 到 PCIe 主机连接器的 High Tech Global 适配器配合使用。ZCU106 电路板需要使用 PL PCIe 而不是 PS PCIe。带有 PL PCIe 的 ZCU106 用于查看 PCIe 事务(这对于 PS PCIe 更具有挑战性)。

image_1

NVMe SSD

Patriot M2 NVMe 128 GB SSD 用于在通用 PCIe x4 到 NVMe M2 承载板中进行测试。

Vivado 系统

ZCU106 的硬件设计采用 XDMA PL PCIe 和硬件一致性生成。在测试的基础上,X86 系统作为硬件一致系统运行,因此 SDPK 不执行高速缓存维护操作。MPSOC 默认为软件一致系统,且必须更改为硬件一致系统才能与 SPDK 一起工作。

XDMA PL PCIe 主端口的 AXI 互连是为基于以下维基页面的硬件一致事务而设置的:

https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18842098/Zynq+UltraScale+MPSoC+Cache+Coherency.

以下摘自 Vivado 原理图的内容说明了添加常量以驱动 axcache 和 axprot 信号以便 PL PCIe 的 AXI 事务具有硬件一致性的方法。

image_2

在 Linux 系统中,采用常量 axcache=0b1011 和 axprot=0b010 使读/写事务具有硬件一致性和非安全性。

嵌入式软件

在 Vivado 生成的 HDF 文件的基础上,采用 PetaLinux 为 ZCU106 电路板构建嵌入式 Linux 系统。将设备树机器设置为 zcu106-reva,以便使用该电路板的网络和 SD 卡等功能。

image_3

在 PetaLinux rootfs 中关闭了对 GStreamer 和 VCU 包的支持,以减少尺寸并缩短构建时间。作为替代方案,可以使用 Vivado 的 HDF 输出(petalinux-config --get-hw-description)来更新 ZCU106 PetaLinux BSP。

SPDK

最新的 SPDK 源代码来自开源库。

image_4

Linux 内核配置和补丁

以下内核配置选项用于在 Linux 中构建内核。

CONFIG_PCIE_XDMA_PL=y

CONFIG_NVME_CORE=y

CONFIG_BLK_DEV_NVME=y

# CONFIG_NVME_MULTIPATH is not set

CONFIG_UIO_PCI_GENERIC=m

# CONFIG_STRICT_DEVMEM is not set

NVMe 驱动程序

对运行 Linux 内核驱动程序的原型进行早期测试可验证在使用 SPDK 之前NVMe SSD 是否正常工作。NVMe 驱动程序被配置为内置到内核中(CONFIG_NVME_CORE=y, CONFIG_BLK_DEV_NVME=y)。

面向 PCI 的 UIO

UIO PCI 驱动程序被配置为内核模块 (CONFIG_UIO_PCI_GENERIC=m)。SPDK 仅将此驱动程序作为内核模块(而不是内置到内核中)使用。

XDMA PL PCIe

内核被配置为包含 PL PCIe 的驱动程序 (CONFIG_XDMA_PL=y)。

Devmem

在调试期间读/写 DDR 的能力是很好的原型制作工具。由于 SPDK 在 DDR 中使用缓存,关闭 devmem 严格性可允许访问 DDR 以进行调试 (# CONFIG_STRICT_DEVMEM)。

PL PCIe Patch

Linux 内核 2019.1 赛灵思版需要为 PL PCIe 驱动程序提供补丁。参见回答记录 72389  https://www.xilinx.com/support/answers/72389.html 并将补丁应用到内核。


SD 卡准备

分区

SD 卡至少有两个分区。第一个分区是普通赛灵思启动文件的 FAT 分区。第 2 个分区应该是 rootfs 的 Linux 分区。16GB SD 卡将有足够的可用空间。下图显示了 fdisk 实用程序创建的 SD 卡的典型分区集。

使用每个分区的适当 mkfs 实用程序格式化 SD 卡分区。


Petalinux 构建

根文件

自承载包

PetaLinux 包含一个自承载包,它提供了构建 SPDK 所需的大部分工具,如GCC 和 make。在 PetaLinux (petalinux-config -c rootfs) 中启用以下包来构建和调试多线程应用。

附加包

在 PetaLinux (petalinux-config -c rootfs) 中启用 libaio 和 kmod(modinfo实用程序)包,因为它们是构建和执行 SPDK 所必需的。

此外,在 rootfs 中也需要 cunit 包,但不是 petalux 菜单系统的一部分,而且必须手动启用它。编辑 <project>/project-spec/meta-user/conf/petalinux-bsp.conf 文件,并将以下行添加到文件中:

IMAGE_INSTALL_append = " cunit cunit-dev"

注释: SPDK 中的单元测试需要 cunit 包。作为构建 cunit 包的替代方案,SPDK 可以配置为不使用以下命令行构建测试:

zcu106$ ./configure --disable-tests

从 SD 启动 Rootfs

PetaLinux 默认为 initramfs rootfs,它对较小的 rootfs 很有用。随着 rootfs 变得越来越大,将 rootfs 放在SD卡上就变得更具挑战性。

更改 PetaLinux 顶级配置 (petalinux-config) 以从 SD 卡上所需的 Linux 分区启动。下图显示了使用 rootfs 的第 3 个分区:

image_6

将 Rootfs 复制到 SD

PetaLinux 为 SD 卡提供多个 rootfs 镜像。将 rootfs.tar.bz 用于原型,如下所示:

$ sudo tar xvjf rootfs.tar.bz2 -C

$ sync

一致性软件安装

硬件一致性要求硬件和软件都要进行更改。以下维基页面的“早期启动时的寄存器写入”部分用于设置软件中的一致性:
https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18842098/Zynq+UltraScale+MPSoC+Cache+Coherency.  

BIF 文件更改

在为普通boot.BIN 生成执行 PetaLinux 包 (petalinux-package --boot) 命令后,项目的构建目录中会存在 bootgen.bif 文件。Bootgen 使用 BIF 文件创建 BOOT.BIN。

将 bootgen.bif 从构建目录复制到 PetaLinux 项目的 images/linux 目录中。编辑文件,删除文件路径,以便它使用 images/linux 目录中的文件。将“[init]regs.init”行添加到文件中,如下面示例所示:

the_ROM_image:

{

        [init] regs.init

        [bootloader, destination_cpu=a53-0] zynqmp_fsbl.elf

        [pmufw_image] pmufw.elf

        [destination_device=pl] design_1_wrapper-coherent.bit

        [destination_cpu=a53-0, exception_level=el-3, trustzone] bl31.elf

        [destination_cpu=a53-0, exception_level=el-2] u-boot.elf

}

寄存器初始化

在上一步中创建的 BIF 文件引用名为 regs.init 的文件,该文件支持早期寄存器初始化。在 PetaLinux 项目的 images/linux 目录中创建此文件,内容如下。

.set. 0xFF41A040 = 0x3;

设置 LPD_SLCR 寄存器的广播内部位将开启内部共享事务从内部域到外部域的广播,并启用硬件一致性。

有关此寄存器初始化的详细信息在引用的维基页面上进行了描述。

BOOT.BIN 生成

PetaLinux 用于使用新的 bif 文件生成 BOOT.BIN,下面的命令假设它从PetaLinux 项目的 images/linux 目录执行。

host$ petalinux-package --boot --bif bootgen.bif --force


ZCU106上的 SPDK

此步骤用于下载、构建(本地)并在 ZCU106 上运行 SPDK。ZCU106 的网络应功能正常,且需要执行以下步骤。文档和详细信息请参见位于 https://spdk.io/ 的 SPDK。

下载源代码

zu106$ git clone https://github.com/spdk/spdk

zu106$ cd spdk

zu106$ git submodule update --init

DPDK

DPDK 必须配置为在没有 NUMA 支持的情况下构建,因为 MPSOC 不是NUMA 架构。将 DPDK 从一个嵌套目录中的 SPDK 复制到另一个非嵌套目录中,以便在 SPDK 之外构建。这样做是因为它似乎是为 MPSOC 配置 DPDK 的最简单方法。

zu106$ cp -Rd spdk/dpdk dpdk

zu106$ cd dpdk

zu106$ edit config/defconfig_arm64-armv8a-linuxapp-gcc adding the following lines.

CONFIG_RTE_EAL_NUMA_AWARE_HUGEPAGES=n

CONFIG_RTE_LIBRTE_VHOST_NUMA=n

zu106$ make config T=arm64-armv8a-linuxapp-gcc

zu106$ make -j 4

SPDK 构建

配置 SPDK 以使用在 SPDK 之外构建的DPDK。然后构建 SPDK。

zu106$ ./configure --with-dpdk=/dpdk/build

zu106$ make -j 4

SPDK 初始化

初始化 SPDK 以解除 NVMe 驱动程序的绑定并绑定 uio_pci_generic 内核模块。

zu106$ su

zu106$ ./scripts/setup.sh

image_7

运行 Hello World

运行 hello world 示例,得到如下所示的典型结果。

zcu106$ ./examples/nvme/hello_world/hello_world

image_8

原型挑战

带有 MPSOC 的第一个硬件原型具有软件一致性,它不适用于 SPDK。Hello world 示例只会超时而不起作用。

通过使用 GDB 逐步执行 hello world 示例可以触摸到数据缓存,以便从高速缓存中刷新它们,并且可以在响应缓存中看到响应。

软件相干系统的 PCIe 事务也使用 ILA 汇集。NVMe 目标从主机存储器读取以从命令队列获取命令。PCIe 事务验证得出 NVMe 目标在从 ZCU106 存储器读取 Identify 命令时得到的全部为零。


性能基线

不需要构建系统来提高性能。以下性能数值仅作为基线。

root@zcu106-ubuntu:/home/xilinx/spdk/examples/nvme/perf# lspci

00:00.0 PCI bridge: Xilinx Corporation Device 9118

01:00.0 Non-Volatile memory controller: Device 1987:5008 (rev 01)

 

root@zcu106-plpcie-106:~/spdk/examples/nvme/perf# ./perf -q 128 -o 4096 -w randread -r 'trtype:PCIe traddr 0000:01:00.0' -t 300

nvme.c: 884:spdk_nvme_transport_id_parse: *ERROR*: Unknown transport ID key 'traddr 0000'

Starting SPDK v19.07-pre / DPDK 19.05.0 initialization...

[ DPDK EAL parameters: perf --no-shconf -c 0x1 --log-level=lib.eal:6 --log-level=lib.cryptodev:5 --log-level=user1:6 --base-virtaddr=0x200000000000 --match-allocations --file-prefix=spdk_pid2879 ]

Initializing NVMe Controllers

Attaching to NVMe Controller at 0000:01:00.0

Attached to NVMe Controller at 0000:01:00.0 [1987:5008]

Associating PCIE (0000:01:00.0) with lcore 0

Initialization complete. Launching workers.

Starting thread on core 0

========================================================

                                                                    Latency(us)

Device Information             :       IOPS      MiB/s    Average        min        max

PCIE (0000:01:00.0) from core 0:  100062.53     390.87    1279.13     703.37 12005575.48

========================================================

Total                          :  100062.53     390.87    1279.13     703.37 12005575.48


结论

SPDK 系统原型的构建和测试只需进行前面几段所示的少量工作。硬件一致系统是为原型制作提供支持所需的唯一硬件更改。使用 PetaLinux 支持的自承载系统可以轻松构建原型软件。位于 https://spdk.io/doc/getting_started.html 的 SPDK 文档提供了原型制作所需的所有细节。

通过少量的原型制作工作,SPDK 可以作为一个系统解决方案进行评估,从而有望通过基于 NVMe 的存储来提高系统的整体性能。


About John Linn

About John Linn

John Linn是来自美国南部的一名战略应用工程师。他是一名嵌入式软件工程师,为赛灵思在全球范围内各个领域(包括电信、A&D 和汽车领域)的客户提供支持。John 在其职业生涯中花了很多年的时间用来研究 BSP 和面向赛灵思 IP 的赛灵思器件驱动程序以及 Linux 内核和U-Boot。