任务并行化使您能够充分利用数据流并行化。与循环并行化相反,当部署任务并行化后,即可允许完全执行单元(任务)并行运行,从而充分利用任务之间带来的额外缓冲。
请参阅以下示例:
void run (ap_uint<16> in[1024],
ap_uint<16> out[1024]
) {
ap_uint<16> tmp[128];
for(int i = 0; i<8; i++) {
processA(&(in[i*128]), tmp);
processB(tmp, &(out[i*128]));
}
}
执行此代码时,processA
函数和 processB
函数将按顺序连续执行 128 次。如果 processA
与 processB
存在组合时延,该循环设置为 278 且总时延可通过如下方式来估算:
额外的周期是因循环建立而产生,并可在“Schedule Viewer”(调度查看器)中查看。
对于 C/C++ 代码,可通过将 DATAFLOW 编译指示添加到 for 循环中来执行任务并行化:
#pragma HLS DATAFLOW
对于 OpenCL API 代码,请将该属性添加到 for 循环之前:
__attribute__ ((xcl_dataflow))
如需了解有关该主题的更多信息,请参阅 数据流最优化、HLS 编译指示 和 OpenCL 编程。
如 HLS 报告中的估算所示,应用此变换将能够通过在任务之间使用双(乒乓)缓冲器方案来有效地显著提升总体性能:
在此案例中,由于并发执行不同迭代的不同任务,使设计的总体时延几乎减半。考虑到每个处理函数有 139 个循环,且 128 个迭代完全重叠,由此所得总时延为:
(1x only processA + 127x both processes + 1x only processB) * 139 cycles = 17931 cycles
使用任务并行度是一种在实现时提升性能的强大方法。但是,将 DATAFLOW 编译指示应用于代码的特定片段和应用于任意片段的效果可能截然不同。通常有必要通过观察个别任务的执行模式来了解 DATAFLOW 编译指示的最终实现结果。最后,Vitis 核开发套件提供了Detailed Kernel Trace(详细的内核追踪),用于展示并发执行情况。
对于此Detailed Kernel Trace,该工具可显示数据流循环的开始,如上图所示。它会演示 processA
在循环开始时立即启动,而 processB
则等待至 processA
完成后才启动其首次迭代的方式。但在 processB
完成循环的首次迭代的同时,processA
就会开始操作第二次迭代,以此类推。
在 时间线轨迹 中为主机和器件活动提供了有关此信息的更抽象的演示。