从一个矩阵乘法的例子一步一步进行功能设计与性能优化。
SDAccel矩阵乘法优化(一)
SDAccel矩阵乘法优化(二)
SDAccel矩阵乘法优化(三)
SDAccel矩阵乘法优化(四)
mmult实现及优化步骤
步骤 | 实现功能 | 关键概念/ Keywords |
---|---|---|
1、cpu实现 | 即在host 端实现简单的矩阵乘法,便于比对数据与性能对比 |
|
2、OpenCL实现 | 在device 端实现基于OpenCL的FPGA矩阵乘法硬件设计. |
Key Concepts - OpenCL APIs |
3、加入Local Memory |
采用 Local Memory 减少数据访存次数 |
Key Concepts - Kernel Optimization - Local Memory |
4、实现读写的突发传输 | 采用突发传输的方式更好的实现DDR 与 Local Memory 数据的读写访问 |
Key Concepts - Kernel Optimization - Burst Read/Write |
5、数组分割 | 通过循环展开与数组分割的方式,实现更好的计算性能 | Key Concepts - Array Partition - Loop Unroll Keywords - xcl_pipeline_loop - xcl_array_partition(complete, dim) - opencl_unroll_hint |
方案分析及优化思路二(Burst Read/Write)
承接第二篇Local Memory
的实现方法进一步进行优化处理,主要解决gmem carry dependency
的问题。在这里,不采用Max Memory Ports
的方法,因为采用多个接口灰消耗大量的LUT资源,并且大大的限制时钟频率的提升。其实,前面分析过了造成gmem carry dependency
的原因,在矩阵乘法的实现过程中,我们完全可以将两个输入的数据分开,不需要在一个for循环中同时进行数据的读取而导致一个for循环在pipeline的过程中需要对两个接口进行读取,进而实现了Burst突发传输。
代码实现
1 |
|
实验结果分析
- vivado hls log文件分析
1 |
|
- HLS Report
- 综合结果分析
* 首先,硬件代码没有优化指令,不需要关注指令是否实现。
* 然后,相比于Local Memory
版本的矩阵乘法实现,Burst Read/Write
的实现方式主要是将两个原本在一个循环体内的输入切分到两个for循环中分开读入。从Pipleline
的角度考虑:第一段for循环pipeline
成功;第二段的for循环只有write_data
的for循环成功,最外层的两个for循环成功完成flatten
但是write_data
与次外层的for循环因为含有LOOP BODY
的原因,无法成功flatten
,因此也无法完成整体的pipeline
;第三段for循环pipeline
成功。
* 从pipeline成功后的II角度考虑:第一段for循环pipeline
后的II=1
,解决了之前gmem carry dependency
的问题;第二三段for循环pipeline
后的II=1
。
- 硬件仿真结果
- 硬件实现结果
参考
xilinx github Xilinx/SDAccel_Examples/cpu_to_fpga
ug1253 SDx Pragma Reference Guide 2017.2
ug1207 SDAccel Environment Optmizaton Guide