Compiling and Linking Host Code with ADF API - 2023.2 English

AI Engine Tools and Flows User Guide (UG1076)

Document ID
UG1076
Release Date
2023-12-04
Version
2023.2 English
When adaptive data flow (ADF) APIs or event profile APIs are used in the host code, you must:
  • Use the registerXRT() API before using the ADF APIs or the event profile APIs in the host code.
  • Compile and link the host code with Work/ps/c_rts/aie_control_xrt.cpp.
The following are example commands for compiling and linking the PS application:
//Compiling host.cpp
$CXX -std=c++17 -O0 -g -Wall -c -I$SDKTARGETSYSROOT/usr/include/xrt/ --sysroot=$SDKTARGETSYSROOT -I./ -I./src -I$XILINX_HLS/include/ -I$XILINX_VITIS/aietools/include -o sw/host.o sw/host.cpp

//Compiling aie_control_xrt.cpp
-std=c++17 -O0 -g -Wall -c -I$SDKTARGETSYSROOT/usr/include/xrt/ --sysroot=$SDKTARGETSYSROOT -I./ -I./src -I$XILINX_HLS/include/ -I$XILINX_VITIS/aietools/include -o sw/aie_control_xrt.o Work/ps/c_rts/aie_control_xrt.cpp

//Linking the host application
$CXX -ladf_api_xrt -lgcc -lc -lpthread -lrt -ldl -lcrypt -lstdc++ -lxrt_coreutil -L$SDKTARGETSYSROOT/usr/lib/ --sysroot=$SDKTARGETSYSROOT -L$XILINX_VITIS/aietools/lib/aarch64.o -o sw/host.exe sw/host.o sw/aie_control_xrt.o
Where -ladf_api_xrt is the required library for the ADF API in Linux.
The following is an example that uses ADF API and event profile API in the host code:
......
#include "adf/adf_api/XRTConfig.h"
#include "xrt/xrt_kernel.h"

#include "graph.cpp"

int run(int argc, char* argv[]){
	......
	char* xclbinFilename = argv[1];
	
	int ret=0;
	// Open xclbin
	auto device = xrt::device(0); //device index=0
	auto uuid = device.load_xclbin(xclbinFilename);
	auto dhdl = xrtDeviceOpenFromXcl(device);

	// s2mm & mm2s kernel handle
	auto s2mm = xrt::kernel(device, uuid, "s2mm");
	auto mm2s = xrt::kernel(device, uuid, "mm2s");

	// output memory
	auto out_bo = xrt::bo(device, output_size_in_bytes, s2mm.group_id(0));
	auto host_out=out_bo.map<int*>();

	// input memory
	auto in_bo = xrt::bo(device, output_size_in_bytes, mm2s.group_id(0));
	auto host_in=in_bo.map<int*>();

	// Initialization input memory
	......

	//kernel run
	auto s2mm_run = s2mm(out_bo, nullptr, OUTPUT_SIZE);//1st run for s2mm has started
	auto mm2s_run = mm2s(in_bo, nullptr, OUTPUT_SIZE);

	// Use registerXRT before ADF API
	adf::registerXRT(dhdl, uuid.get());
	std::cout<<"Register XRT"<<std::endl;

	event::handle handle = event::start_profiling(gr.dataout, event::io_stream_start_to_bytes_transferred_cycles, output_size_in_bytes);
	if(handle==event::invalid_handle){
		printf("ERROR:Invalid handle. Only two performance counter in a AIE-PL interface tile\n");
		return 1;
	}

	gr.run(iterations);
	gr.end();
	s2mm_run.wait();
	// Wait graph for some cycles
	long long cycle_count = event::read_profiling(handle);
	std::cout<<"cycle count:"<<cycle_count<<std::endl;
	event::stop_profiling(handle);
	double throughput = (double)output_size_in_bytes / (cycle_count *0.8 * 1e-3); //Every AIE cycle is 0.8ns in production board
	std::cout<<"Throughput of the graph: "<<throughput<<" MB/s"<<std::endl;
	out_bo.sync(XCL_BO_SYNC_BO_FROM_DEVICE);

	//post processing
        ......

	return ret;
}

int main(int argc, char* argv[])
{
	try {
		auto match = run(argc, argv);
		std::cout << "TEST " << (match ? "FAILED" : "PASSED") << "\n";
		return (match ? EXIT_FAILURE :  EXIT_SUCCESS);
	}	
		catch (std::exception const& e) {
		std::cout << "Exception: " << e.what() << "\n";
		std::cout << "FAILED TEST\n";
		return 1;
	}
}