在主机代码中分配 DDR 存储体 - 2022.1 简体中文

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

Document ID
UG1393
Release Date
2022-05-25
Version
2022.1 简体中文
重要: 这是可选操作,仅在下述特殊情况下才需要执行。

Vitis 工具流程中,内核端口到存储体的连接可使用 --connectivity.sp 开关来建立,如 将内核端口映射到存储器 中所述。由 v++ 生成的 xclbin 包含有关内核端口到存储器的连接信息,以便 XRT 能够正确分配缓冲器。在主机代码中创建缓冲器时,XRT 会自动将缓冲器从内核 xclbin 分配到存储器,并在内部管理这些缓冲器。如果将单个内核端口连接到多个存储体,那么 XRT 始终从编号较低的存储体开始操作。

在大部分情况下,此方法足以满足需求。但在某些特殊情况下,您可能需要在主机代码中手动分配缓冲器位置(或特殊属性)。为此,赛灵思 OpenCL 供应商扩展程序提供了名为 CL_MEM_XRT_PTR_XILINX 的缓冲器扩展程序,专用于管理主机代码中的存储体分配。以下代码示例显示了将输入和输出缓冲器分配到 DDR 存储体 0 和存储体 1 所需的头文件和代码:

#include <CL/cl_ext.h>
…
int main(int argc, char** argv) 
{
…
    cl_mem_ext_ptr_t inExt, outExt;  // Declaring two extensions for both buffers
    inExt.flags  = 0|XCL_MEM_TOPOLOGY; // Specify Bank0 Memory for input memory
    outExt.flags = 1|XCL_MEM_TOPOLOGY; // Specify Bank1 Memory for output Memory
    inExt.obj = 0   ; outExt.obj = 0; // Setting Obj and Param to Zero
    inExt.param = 0 ; outExt.param = 0;

    int err;
    //Allocate Buffer in Bank0 of Global Memory for Input Image using Xilinx Extension
    cl_mem buffer_inImage = clCreateBuffer(world.context, CL_MEM_READ_ONLY | CL_MEM_EXT_PTR_XILINX,
            image_size_bytes, &inExt, &err);
    if (err != CL_SUCCESS){
        std::cout << "Error: Failed to allocate device Memory" << std::endl;
        return EXIT_FAILURE;
    }
    //Allocate Buffer in Bank1 of Global Memory for Input Image using Xilinx Extension
    cl_mem buffer_outImage = clCreateBuffer(world.context, CL_MEM_WRITE_ONLY | CL_MEM_EXT_PTR_XILINX,
            image_size_bytes, &outExt, NULL);
    if (err != CL_SUCCESS){
        std::cout << "Error: Failed to allocate device Memory" << std::endl;
        return EXIT_FAILURE;
    }
…
}

扩展指针 cl_mem_ext_ptr_tstruct,定义如下:

typedef struct{
    unsigned flags;
    void *obj;
    void *param;
  } cl_mem_ext_ptr_t;
  • flags 的有效值为:
    • XCL_MEM_DDR_BANK0
    • XCL_MEM_DDR_BANK1
    • XCL_MEM_DDR_BANK2
    • XCL_MEM_DDR_BANK3
    • <id> | XCL_MEM_TOPOLOGY
      注释: <id> 是通过观察生成的 xxx.xclbin.info 文件(位于 xxx.xclbin 文件旁)的“Memory Configuration”(存储器配置)部分来确定的。在 xxx.xclbin.info 文件中,列出的全局存储器(DDR、HBM、PLRAM 等)都带有表示 <id> 的索引。
  • obj 是指向关联主机存储器的指针,仅当 CL_MEM_USE_HOST_PTR 标志传递到 clCreateBuffer API 时才会为 CL 存储缓冲器分配主机存储器,否则它设置为 NULL。
  • param 保留以供将来使用。始终为其赋值 0 或 NULL。

以下是您可能需要使用扩展指针的部分特殊情况:

P2P 缓冲器
要获取解释和示例,请参阅 https://xilinx.github.io/XRT/master/html/p2p.html
主机存储缓冲器
要获取解释和示例,请参阅 https://xilinx.github.io/XRT/master/html/hm.html
当内核端口连接到多个存储体时,请向特定存储体分配主机缓冲器
例如,DDR[0:1]。在Vitis 最优化 FPGA 加速应用:布隆过滤器示例教程的使用多个 DDR 存储体实践中详述了此用例。

向特定存储体分配主机缓冲器的示例

上述第三个用例的示例是,当主机和内核同时访问 DDR 存储体时,如果您想要进行数据拆分以使内核与主机以乒乓方式来访问存储体,则可能需要使用 cl_mem_ext_ptr_t。当主机对特定存储体进行读写时,内核从另一个存储器执行读写,这样这些主机/内核访问就不会产生争用而影响性能。在此情况下,您必须自行管理缓冲器分配。

xclbin 中的内核端口连接到 DDR bank1 和 bank2,并从其中任一存储体读取数据。此连接是在链接期间由 Vitis 编译器使用 --connectivity.sp 开关来建立的:

[connectivity]
sp=runOnfpga_1.input_words:DDR[1:2]

从主机代码,可向 DDR 存储体 1 或 2 发送 input_words 数据。这样会创建 2 个赛灵思扩展指针 (cl_mem_ext_ptr_t) 对象,如以下代码示例所示。对象标志将确定每个缓冲器将分配到哪个 DDR 存储体以供内核进行访问。内核实参可设置为 input_words[0]input_words[1] 以供执行连续内核排队。

#include <CL/cl_ext.h>
…
int main(int argc, char** argv) 
{
cl_mem_ext_ptr_t buffer_words_ext[2];

buffer_words_ext[0].flags = 1 | XCL_MEM_TOPOLOGY; // DDR[1]
buffer_words_ext[0].param = 0;
buffer_words_ext[0].obj   = input_doc_words;
buffer_words_ext[1].flags = 2 | XCL_MEM_TOPOLOGY; // DDR[2]
buffer_words_ext[1].param = 0;
buffer_words_ext[1].obj   = input_doc_words;
…