在 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_t
为 struct
,定义如下:
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;
…