含 ADF API 和 XRT API 的主机代码参考 - 2022.1 简体中文

Versal ACAP AI 引擎编程环境 用户指南 (UG1076)

Document ID
UG1076
Release Date
2022-05-25
Version
2022.1 简体中文

本节提供了 XRT API 的汇总信息,这些 API 用于控制 PL 内核与 graph 以及 ADF API 与 XRT API 之间的映射关系。此外还提供了完整的主机代码以供参考,这些主机代码使用 ADF API 或 XRT API 来控制 graph。

注释: 本节仅列出部分 API。如需了解有关 XRT API 的最新详细信息,请访问 https://github.com/xilinx/xrt
表 1. XRT API
XRT API 描述
类别:器件句柄 (experimental/xrt_device.h)
xrtDeviceHandle xrtDeviceOpen(unsigned int index); 打开器件并获取其句柄。
xrtDeviceHandle xrtDeviceOpenFromXcl(xclDeviceHandle xhdl); xclDeviceHandle 获取器件处理。
int xrtDeviceClose(xrtDeviceHandle dhdl); 关闭已打开的器件。
int xrtDeviceLoadXclbinFile(xrtDeviceHandle dhdl, const char* xclbin_fnm); 读取和加载 XCLBIN 文件。
void xrtDeviceGetXclbinUUID(xrtDeviceHandle dhdl, xuid_t out); 获取器件上加载的 XCLBIN 镜像的 UUID。
类别:PL 内核句柄 (experimental/xrt_kernel.h)
xrtKernelHandle xrtPLKernelOpen(xrtDeviceHandle deviceHandle, const xuid_t xclbinId, const char *name); 打开 PL 内核并获取其句柄。
int xrtKernelClose(xrtKernelHandle kernelHandle); 关闭已打开的内核。
xrtRunHandle xrtKernelRun(xrtKernelHandle kernelHandle, ...); 启动内核执行。
xrtRunHandle xrtRunOpen(xrtKernelHandle kernelHandle); 为内核打开新的运行句柄,但不启动内核。
int xrtRunSetArg(xrtRunHandle rhdl, int index, ...); 为这轮运行设置特定的内核实参。
int xrtRunUpdateArg(xrtRunHandle rhdl, int index, ...); 异步更新内核实参。
int xrtRunStart(xrtRunHandle rhdl); 启动现有运行句柄。
enum ert_cmd_state xrtRunWait(xrtRunHandle rhdl); 等待运行完成。
int xrtRunClose(xrtRunHandle rhdl); 关闭运行句柄。
类别:graph 句柄 (experimental/xrt_graph.h)
xrtGraphHandle xrtGraphOpen(xrtDeviceHandle handle, const uuid_t xclbinUUID, const char *graphName); 打开 graph 并获取其句柄。
void xrtGraphClose(xrtGraphHandle gh); 关闭已打开的 graph。
int xrtGraphRun(xrtGraphHandle gh, int iterations); 启动 graph 执行。
int xrtGraphWait(xrtGraphHandle gh, uint64_t cycle); 等待指定的 AI 引擎周期数(从上次 xrtGraphRun 起),然后停止 graph。如果 cycle 为 0,则等待至 graph 完成。如果 graph 运行周期数已超过指定周期数,则立即停止 graph。
int xrtGraphResume(xrtGraphHandle gh); 恢复暂挂的 graph。
int xrtGraphEnd(xrtGraphHandle gh, uint64_t cycle); 等待指定的 AI 引擎周期数(从上次 xrtGraphRun 起),然后终止 graph。如果 cycle 为 0,则等待至 graph 完成,然后再将其终止。如果 graph 运行周期数已超过指定周期和结束数,则立即停止 graph,然后将其终止。
int xrtGraphUpdateRTP(xrtGraphHandle gh, const char *hierPathPort, const char *buffer, size_t size); 以分层名称更新端口的 RTP 值。
int xrtGraphReadRTP(xrtGraphHandle gh, const char *hierPathPort, char *buffer, size_t size); 以分层名称读取端口的 RTP 值。
类别:AIE 句柄 (experimental/xrt_aie.h)
int xrtAIESyncBO(xrtDeviceHandle handle, xrtBufferHandle bohdl, const char *gmioName, enum xclBOSyncDirection dir, size_t size, size_t offset); 在 DDR 存储器与接口拼块 DMA 通道之间传输数据。
类别:缓冲器对象句柄 (experimental/xrt_bo.h)
xrtBufferHandle xrtBOAlloc(xrtDeviceHandle dhdl, size_t size, xrtBufferFlags flags, xrtMemoryGroup grp); 以相应的标志按请求大小分配 BO。
int xrtBOFree(xrtBufferHandle bhdl); 清空/取消分配已分配的 BO。
int xrtBOSync(xrtBufferHandle bhdl, enum xclBOSyncDirection dir, size_t size, size_t offset); 按请求方向同步缓冲器内容。
void* xrtBOMap(xrtBufferHandle bhdl); 存储器映射 BO 到用户地址空间内。
类别:错误报告 (experimental/xrt_error.h)
int xrtErrorGetLast(xrtDeviceHandle handle, xrtErrorClass ecl, xrtErrorCode* error, uint64_t* timestamp); 获取最新错误代码及其给定错误类的时间戳。
int xrtErrorGetString(xrtDeviceHandle, xrtErrorCode error, char* out, size_t len, size_t* out_len); 获取给定错误代码的描述字符串。

下表列出了 ADF API 与 XRT API 之间的映射。xrtGraphOpen()xrtPLKernelOpen()xrtRunOpen()xrtKernelClose() XRT API 按需在 ADF API 内部进行调用,且不列出对应的映射。

表 2. ADF API 和 XRT API 映射
Graph API XRT API
graph::run() xrtGraphRun(xrtGraphHandle, 0),用于 AI 引擎
graph::run(iterations) xrtGraphRun(xrtGraphHandle, iterations),用于 AI 引擎
graph::wait() xrtGraphWait(xrtGraphHandle, 0),用于 AI 引擎
graph::wait(aie_cycles) xrtGraphWait(xrtGraphHandle aie_cycles),用于 AI 引擎
graph::resume() xrtGraphResume(xrtGraphHandle)
graph::end() xrtGraphEnd(xrtGraphHandle, 0),随后 xrtGraphClose(xrtGraphHandle),用于 AI 引擎
graph::end(aie_cycles) xrtGraphEnd(xrtGraphHandle, aie_cycles),随后 xrtGraphClose(xrtGraphHandle),用于 AI 引擎
graph::update() xrtGraphUpdateRTP(),用于 AI 引擎
graph::read() xrtGraphReadRTP(),用于 AI 引擎
GMIO::malloc() xrtBOAlloc()xrtBOMap()
GMIO::free() xrtBOFree()
GMIO::gm2aie_nb() 不适用
GMIO::aie2gm_nb() 不适用
GMIO::wait() 不适用
GMIO::gm2aie() xrtSyncBOAIE(...,XCL_BO_SYNC_BO_GMIO_TO_AIE,...)
GMIO::aie2gm() xrtSyncBOAIE(...,XCL_BO_SYNC_BO_AIE_TO_GMIO,...)
adf::event API,用于剖析和事件追踪 不适用

以下是使用 ADF API 和 XRT API 的主机代码,以供参考。__USE_ADF_API__ 是代码中用户定义的宏,可用于在 ADF API 与 XRT API 之间进行切换,以控制 AI 引擎 graph。

#include <stdlib.h>
#include <fstream>
#include <iostream>
#include "host.h"
#include <unistd.h>
#include <complex>
#include "adf/adf_api/XRTConfig.h"
#include "experimental/xrt_kernel.h"

#include "graph.cpp"

#define OUTPUT_SIZE 2048

using namespace adf;

int main(int argc, char* argv[]) {

    size_t output_size_in_bytes = OUTPUT_SIZE * sizeof(int);

    //TARGET_DEVICE macro needs to be passed from gcc command line
    if(argc != 2) {
	printf("Usage: %d <xclbin>\r\n",argv[0]);
	return EXIT_FAILURE;
    }
    char* xclbinFilename = argv[1];
	
    int ret;
    // Open xclbin
    auto dhdl = xrtDeviceOpen(0);//device index=0
    if(!dhdl){
	printf("Device open error\n");
    }
    ret=xrtDeviceLoadXclbinFile(dhdl,xclbinFilename);
    if(ret){
	printf("Xclbin Load fail\n");
    }
    xuid_t uuid;
    xrtDeviceGetXclbinUUID(dhdl, uuid);
    
    // output memory
    xrtBufferHandle out_bohdl = xrtBOAlloc(dhdl, output_size_in_bytes, 0, /*BANK=*/0);
    std::complex<short> *host_out = (std::complex<short>*)xrtBOMap(out_bohdl);

    // s2mm ip
    xrtKernelHandle s2mm_khdl = xrtPLKernelOpen(dhdl, uuid, "s2mm");
    xrtRunHandle s2mm_rhdl = xrtRunOpen(s2mm_khdl);
    xrtRunSetArg(s2mm_rhdl, 0, out_bohdl);
    xrtRunSetArg(s2mm_rhdl, 2, OUTPUT_SIZE);
    xrtRunStart(s2mm_rhdl);
    printf("run s2mm\n");

#if __USE_ADF_API__
    // update graph parameters (RTP) & run
    adf::registerXRT(dhdl, uuid);
    printf("Register XRT\r\n");
    int narrow_filter[12] = {180, 89, -80, -391, -720, -834, -478, 505, 2063, 3896, 5535, 6504};
    int wide_filter[12] = {-21, -249, 319, -78, -511, 977, -610, -844, 2574, -2754, -1066, 18539};
    gr.run(16);//start AIE kernel   
    gr.update(gr.fir24.in[1], narrow_filter, 12);//update AIE kernel RTP
    printf("Update fir24 done\r\n");
    printf("Graph run done\r\n");
    gr.wait(); // wait for AIE kernel to complete
    printf("Graph wait done\r\n");    
    gr.update(gr.fir24.in[1], wide_filter, 12);//Update AIE kernel RTP
    printf("Update fir24 done\r\n");
    gr.run(16);//start AIE kernel
    printf("Graph run done\r\n");
#else
    int narrow_filter[12] = {180, 89, -80, -391, -720, -834, -478, 505, 2063, 3896, 5535, 6504};
    int wide_filter[12] = {-21, -249, 319, -78, -511, 977, -610, -844, 2574, -2754, -1066, 18539};
    auto ghdl=xrtGraphOpen(dhdl,uuid,"gr");
    if(!ghdl){
	printf("Graph Open error\r\n);;
    }else{
	printf("Graph Open ok\r\n");;
    }
    int size=1024;
    xrtKernelHandle noisegen_khdl = xrtPLKernelOpen(dhdl, uuid, "random_noise");
    xrtRunHandle noisegen_rhdl = xrtRunOpen(noisegen_khdl);
    xrtRunSetArg(noisegen_rhdl, 1, size);
    xrtRunStart(noisegen_rhdl);
    printf("run noisegen\n");
    ret=xrtGraphUpdateRTP(ghdl,"gr.fir24.in[1]",(char*)narrow_filter,12*sizeof(int));
    if(ret!=0){
	printf("Graph RTP update fail\n");
	return 1;
    }
    ret=xrtGraphRun(ghdl,16);
    if(ret){
	printf("Graph run error\r\n");
    }else{
	printf("Graph run ok\r\n");
    }
    ret=xrtGraphWait(ghdl,0);
    if(ret){
	printf("Graph wait error\r\n");
    }else{
	printf("Graph wait ok\r\n");
    }
    xrtRunWait(noisegen_rhdl);
    xrtRunSetArg(noisegen_rhdl, 1, size);
    xrtRunStart(noisegen_rhdl);
    printf("run noisegen\n");
    ret=xrtGraphUpdateRTP(ghdl,"gr.fir24.in[1]",(char*)wide_filter,12*sizeof(int));
    if(ret!=0){
	printf("Graph RTP update fail\n");
	return 1;
    }
    ret=xrtGraphRun(ghdl,16);
    if(ret){
	printf("Graph run error\r\n");
    }else{
	printf("Graph run ok\r\n");
    }
#endif
    // wait for s2mm done
    auto state = xrtRunWait(s2mm_rhdl);
    printf("s2mm completed with status %d\r\n",state);
	
    xrtBOSync(out_bohdl, XCL_BO_SYNC_BO_FROM_DEVICE , output_size_in_bytes,/*OFFSET=*/ 0);

    std::ofstream out("out.txt",std::ofstream::out);
    std::ifstream golden("data/filtered.txt",std::ifstream::in);
    short g_real=0,g_imag=0;
    int match = 0;
    for (int i = 0; i < OUTPUT_SIZE; i++) {
	golden >> std::dec >> g_real;
	golden >> std::dec >> g_imag;
	if(g_real!=host_out[i].real() || g_imag!=host_out[i].imag()){
		
          printf("ERROR: i=%d gold.real=%d gold.imag=%d out.real=%d out.imag=%d\r\n",i,g_real,g_imag,host_out[i].real(),host_out[i].imag());
		match=1;
	}
	out<<host_out[i].real()<<" "<<host_out[i].imag()<<" "<<std::endl;
    }
    out.close();
    golden.close();

#if __USE_ADF_API__
    gr.end();
#else
    ret=xrtGraphEnd(ghdl,0);
    if(ret){
	printf("Graph end error"\r\n);;
    }
    xrtRunClose(noisegen_rhdl);
    xrtKernelClose(noisegen_khdl);
    xrtGraphClose(ghdl);
#endif
    xrtRunClose(s2mm_rhdl);
    xrtKernelClose(s2mm_khdl);
    xrtBOFree(out_bohdl);
    xrtDeviceClose(dhdl);


    char pPass[]= "PASSED";
    char pFail[]= "FAILED";
    char* presult;
    presult = (match ? pFail : pPass); 
    printf("TEST %s\r\n",presult);

    return (match ? EXIT_FAILURE :  EXIT_SUCCESS);
}

XRT API 具有 C 语言和 C++ 语言版本,用于控制 PL 内核。如需了解有关 XRT API 的 C++ 语言版本的更多信息,请参阅 XRT 本机 API