使用主机指针缓冲器 - 2023.2 简体中文

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

Document ID
UG1393
Release Date
2023-12-13
Version
2023.2 简体中文
重要: 对于嵌入式平台,不建议使用 CL_MEM_USE_HOST_PTR。嵌入式平台需持续性存储器分配,应使用 CL_MEM_ALLOC_HOST_PTR 方法,如 由 XRT 分配缓冲器 中所述。

cl_mem 对象包含 2 个主要部分:主机侧指针和器件侧指针。在内核开始操作之前,器件侧指针是在器件侧存储器上(例如,在器件的全局存储器内部的特定位置)隐式分配的,而缓冲器则驻留在器件上。使用 clEnqueueMigrateMemObjects 意味着先执行此分配并进行数据传输,并且这两项操作远早于内核执行。如果主机多次对相同内核执行操作,那么这对于软件流水打拍非常有帮助,因为当内核仍在对前一个数据集执行操作的同时,即可为后一项传输事务执行数据传输,从而将连续内核执行的数据传输时延隐藏起来。

OpenCL 框架可提供大量 API,用于在主机和器件之间传输数据。通常,数据传输 API(如 clEnqueueWriteBufferclEnqueueReadBuffer)会在存储器对象完成排队后,将这些对象隐式移植到器件中。由于这些 API 无法保证何时进行数据传输,导致主机应用难以将存储器对象的移动与对数据执行的计算进行同步。

AMD 建议使用 clEnqueueMigrateMemObjects 代替 clEnqueueWriteBufferclEnqueueReadBuffer 以提升性能。通过使用此 API 即可在执行相关命令之前显式执行存储器移植。这样主机应用即可通过常规命令队列调度来抢先更改存储器对象的关联,从而为其他后续命令做好准备。这样还可支持应用在实际需要使用存储器对象之前,将这些存储器对象的布局与其他不相关操作进行重叠,从而隐藏或者减小数据传输时延。当与 clEnqueueMigrateMemObjects 关联的事件被标记为完成后,主机程序即可知晓这些存储器对象已成功完成移植。

提示: clEnqueueMigrateMemObjects 的另一大优势在于它可在单次 API 调用内移植多个存储器对象。这样即可减小通过调度和调用函数来为多个存储器对象传输数据所需的开销。

以下代码显示了 clEnqueueMigrateMemObjects 的用法:

int host_mem_ptr[MAX_LENGTH]; // host memory for input vector
      
// Fill the memory input
for(int i=0; i<MAX_LENGTH; i++) {
  host_mem_ptr[i] = <... >   
}

cl_mem dev_mem_ptr = clCreateBuffer(context,  
    				 CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR,
    				 sizeof(int) * number_of_words, host_mem_ptr, NULL); 

clSetKernelArg(kernel, 0, sizeof(cl_mem), &dev_mem_ptr); 

err = clEnqueueMigrateMemObjects(commands, 1, dev_mem_ptr, 0, 0, 
	  NULL, NULL);