加速器的异步主机控制 - 2023.2 简体中文

Vitis 统一软件平台文档 应用加速开发 (UG1393)

Document ID
UG1393
Release Date
2023-12-13
Version
2023.2 简体中文

VSC 模式允许利用包含用户定义的硬件流水线的 CU 对加速器进行编译,如 构建硬件 中所述。此类流水线由通过 AXI4‑Stream 彼此相连的 PE 组成,并且也可以连接到平台端口(AXI4 连接),例如,全局存储器或 I/O 接口(如以太网 QSFP 端口)。平台将提供 IP 用于将此类接口转换为 AXI4‑Stream 端口,这些端口即可连接到用户定义的流水线中的 PE。

通过使用 VSC,即可在运行时从主机 CPU 中运行的应用,将此类硬件流水线轻松配置为动态更改处理行为。以下描述了此类加速器的创建方式。下图中显示了系统组合示例。

图 1. 加速器实现

Eth_RxEth_Tx 模块通常为平台 IP,用于将 AXI4‑Stream 码字转换为以太网包。这些模块也可能是含用户定义的 AXI4 接口的定制 IP。

加速器流水线其余部分则是通过 VSC 使用 AXI4‑Stream 连接来创建的,如白框中所示。流水线中的 PE 均为用户定义的功能,例如,包处理功能(如互联网协议包筛选器)。在此示例中,有一条创建的流水线包含两项任务,即分别名为 modsmp 的 PE。此外,系统还包含另一个控制 PE,其中具有到这些流水线 PE 的 AXI4‑Stream 连接。以下提供的加速器代码示例中,左侧为 .hpp 文件,右侧则是 .cpp 文件。

// -- file: ETH.hpp --
#include "vpp_acc.hpp"
class ETH : public VPP_ACC<ETH,1>
{
public:
    ZERO_COPY(dIn);
    ZERO_COPY(dOut);

    SYS_PORT(dIn,  MEM_BANK0);
    SYS_PORT(dOut, MEM_BANK1);

    FREE_RUNNING(fsk_mod);
    FREE_RUNNING(fsk_smp);
    FREE_RUNNING(eth_rx);
    FREE_RUNNING(eth_tx);
    
    static void compute(int cmd, Pkt* dIn, Pkt* dOut);

    static void control(...
    static void fsk_mod(...
    static void fsk_smp(...
    static void eth_tx(...
    static void eth_rx(...
};
// -- file: ETH.cpp --
void ETH::compute(int cmd, Pkt* dIn, Pkt* dOut)
{
    static IntStream dropS("drop");
    static IntStream addS("add");
    static IntStream reqS("req");
    static PktStream smpS("smp");
    static BitStream getS("get");
    static IntStream sntS("snt");
    static PktStream Ax("Ax", /*post_check=*/false);
    static PktStream Bx("Bx", /*post_check=*/false);
    static PktStream Cx("Cx", /*post_check=*/false);
    
    control(cmd, dIn, dOut,
            dropS, addS, reqS, smpS, getS, sntS);
    eth_rx (Ax);
    fsk_mod(Ax, Bx, dropS, addS);
    fsk_smp(Bx, Cx, reqS, smpS);
    eth_tx (Cx, getS, sntS);
}

在此示例中,定义了 5 个 PE,包括 eth_txeth_rx 用于模仿 AXI4‑Stream 中的接收码字和发射码字中的平台 IP 行为。compute() 作用域在这些 PE 之间使用 AXI4‑Stream 连接来实现加速器流水线。control PE 可在这些串流上发送命令码字,而任务 PE(fsk_modfsk_smp)则监控这些命令 AXI4‑Stream 并通过更改行为来做出响应。fsk_smp PE 的响应方式则是对请求的包数量进行采样并返回给 control PE。fsk_mod PE 的响应方式是给包数据添加值,或者丢弃从 Eth_Rx 传递到 Eth_Tx 的包。

流水线 PE fsk_modfsk_smp, 属于 FREE_RUNNING 的 PE(如 指南宏 中所述),因为这些 PE 永不停止,并按其输入串流中的码字来驱动其操作。

control PE 通过两条 SYS_PORT 连接与主机 CPU 进行沟通,这两条连接分别对应于输入 (dIn) 和输出 (dOut) 的接口实参数据指针,以及标量命令实参 (cmd)。control PE 并非自由运行,且会对来自主机 CPU 的 compute() 调用做出响应。此系统组合完全由用户定义,包括命令的性质以及对应的 PE 功能。

此处显示了主机代码快照,在 GitHub 上还提供了完整示例。

// -- file: host.cpp --
#include "vpp_acc_core.hpp" // required
#include "ETH.hpp"
int config_sample(int sz)
{
    printf("main: sample %d\n", sz);

    Pkt* sample  = (Pkt*)ETH::alloc_buf(sz * sizeof(Pkt), vpp::output);
    Pkt* config  = (Pkt*)ETH::alloc_buf(sizeof(Pkt), vpp::input);
    config[0].dt = sz;

    auto fut = ETH::compute_async(cmd_sample, config, sample);
    fut.get();
    print_sample(sample, sz);
    int pkt_nr = sample[0].nr;
    ETH::free_buf(config);
    ETH::free_buf(sample);
    return pkt_nr;
}

由 VSC 主机代码所发出的作业命令(尤其是使用 compute_async() API 发出的命令)支持控制 PE 转换此命令并通过命令串流将配置码字按序传递到流水线 PE。此快照显示了发出包采样命令的用户定义 API。必需的 szsample 缓冲器是在运行时分配的,compute_async() 调用将触发控制 PE 以捕获包的 sz 数量,并将码字返回到主机。由 compute() 返回的 fut 在主机代码中保持阻塞状态,直至结果可用为止。但 compute_async() 正如其名,表示触发加速器的异步调用。一旦采样的码字返回并经主机处理后,即可清空对应的缓冲器。

在此例中,由于主机控制并非 compute 作业的连续流水线,而只是偶发的非时序关键型作业,因此 send_while/receive_all 线程将不会对其加以管理。改由应用使用 vpp_acc_core.hpp 中定义的 compute_async() API 来管理同步。

重要:vpp_acc_core.hpp 头文件只需包含在主机代码文件内,并置于所包含的任何 vpp_acc.hpp 之前即可。

通过 VSC,即可从主机 CPU 对此类硬件流水线进行组合与异步控制。此类加速器的应用方式之一是 NIC 卡上的包处理加速器。例如,X3 Hybrid 平台可提供以太网发射和接收 IP,通过 MAC 接口将到达 QSFP 端口的以太网数据包转换为 AXI4‑Stream。此外,NIC 接口允许加速器通过 PCIe 向已连接的主机 CPU 提供数据,或者可使用主机到存储器的访问通过 PCIe 来直接访问主机 CPU 存储器。通过使用 VSC,集合在 PL 上组合加速器数据包处理流水线,并且可由 CPU 通过 PCIe 来进行异步控制。