采用高层次综合(HLS)时既要关注Directive(也就是Pragmas)的设置,也要关注代码风格。而且,有时从代码层面对设计进行优化往往会更有助于获得期望的性能。我们来看一个例子,如下图代码所示。
这个例子很简单,完成的就是数组所有元素的和,需要说明的是这里数组长度为1024,数据类型DIT为float。浮点和定点的加法是不一样的。
采用HLS综合,solution1:不添加任何Directive;Solution2:对for循环设置Pipeline,结果对比如下。可以看到即便是Solution2,Interval也达到了5123。
为了降低Latency,改善Interval,我们先从代码层面着手。
第一次优化
优化后的代码如下图所示。
这里,嵌套的for循环完成的操作如下图所示。tmp[0]完成din[0], din[8], …,din[1016]的和;tmp[1]完成din[1], din[9], …, din[1017]的和,依此类推。
同时,设置如下Directives:将数组tmp打散;嵌套for循环的外层设置pipeline;将第二个for循环展开(Unroll)。
创建两个Solution:Solution1:不添加任何Directive;Solution2:添加上述三个Directives,综合后的性能对比如下图所示。可以看到优化后的代码,其Interval已经从5123降到了693。
还可以注意到,两个for循环之间(嵌套的for循环和第二个独立的for循环)可以应用DATAFLOW,从而可进一步降低Latency和Interval。
第二次优化
进一步优化,将第二个for循环手工展开,如下图所示。
Directive的设置:将数组tmp打散;嵌套for循环的外层设置pipeline。此时,综合后的性能如下图所示。
第三次优化
将第二个for循环手工展开,并同时利用括号实现两两相加,如下图所示。
此时,Interval进一步降低至668。
由此,可以得出一个这样的结论:
相比于 float s =(a+b+c+d), float s =((a+b)+(c+d))可获得更好的性能。
可以看到,第一次代码优化外加一些Directives可获得最佳的性能,而第二次代码优化和第三次代码优化并没有带来性能的明显改善。那么是否可以不修改代码而只是设置Directive来获得更好的性能呢?