vivado HLS 优化总结以及相关流程

一、for 循环优化之pipeline

vivado HLS 优化总结以及相关流程

二、for 循环优化之unroll

在默认情况下 for 循环是折叠的(rolled),可以理解为每次循环都使用同一套电路,每
次循环分时复用。如果展开,则循环电路被复制若干份,具体数量可以通过参数设置。这些
复制出的电路可以同时执行不同的数据。
vivado HLS 优化总结以及相关流程

三、for 循环优化之merge

vivado HLS 优化总结以及相关流程
在上图示例中,loop_region 是一个用花括号括起来的区域。这里因为两个 loop 都是对
a 和 b 两个数组进行计算,所以可以通过 LOOP_MERGE 指定进行合并优化。
在合并之前两个 Loop 分别为 8 个周期,再加上进入和退出循环的时间消耗,所以整个
过程消耗 2*(8+1)=18 个时钟周期。合并之后整个循环消耗 8 个时钟周期,整个函数消耗
9 个时钟周期。由此可见循环的合并可以在一定程度上降低 latency,这是因为在默认的情况
下 for 循环会创建额外的状态机,而额外的状态机会占用额外的时钟周期以及额外的资源,
所以导致 latency 和资源的用量会有所增加。因此合并之后这两个方面都会降低。

四、for 循环优化之数据流DataFlow

vivado HLS 优化总结以及相关流程
可以看出数组 A 通过 Task A 生成数组 x,数组 x 通过 Task B 生成数组 y,数组 y 通过
Task C 生成数组 C,其数据流向图如图 17-2 所示。所以 Task A、B、C 之间是有数据依赖关
系的,所以可以用 pipeline 进行优化,但是因为有数据依赖关系,所以不能进行合并优化。
vivado HLS 优化总结以及相关流程
在示例 1 的情况中,刚好可以用到 DATAFLOW 数据流优化方法。数据流优化就是在三
个循环之间插入 Channel(可以是 Ping-pong RAM、FIFO 或 Register)。
vivado HLS 优化总结以及相关流程
在没有使用 DATAFLOW 时,三个循环顺序执行,是没有交叠的。DATAFLOW 之后是的
在执行 Loop B 的时候并不需要等到 Loop A 完全执行完之后再开始,只要 A 有输出,就可
以利用这个输出去执行 Loop B。这样多个任务之间就可以有交叠,降低了 latency,提高了
数据吞吐率。
vivado HLS 优化总结以及相关流程

五、for 循环优化之嵌套循环优化

对内部循环 pipeline,则会自动对循环做 LOOP_FLATTEN 优化,即把所有的嵌套循
环展开(flatten)为一个大循环。

unroll 展开和 flatten 展开是不一样的概念。unroll 是将循环体展开为并行操作,而
flatten 是将嵌套循环展开为单一循环。

六、数组优化 - - 数组分割

数组最终都会以 memory 的形式实现(RAM、ROM 或 FIFO)。如果这个数组作为顶层
函数的形参,那么最终就会以相应的 memory 接口形式呈现,包括相应的读写地址和数据以
及读写使能。如果数组在设计内部,最终就会映射为真正的 block RAM,LUTRAM,UltraRAM
或者 register,具体类型取决于在设计中使用的优化方法。
用 memory 或 memory ports 实现的数组往往是设计中的性能瓶颈。
Vivado HLS 提供了 3 种对数组分割的方法,分别是 block,cyclic 和 complete。block 分
割就是将数组元素分割为指定块数,然后依次填满每一块。Cyclic 方法就是分割为指定块数
后先每块分配一个元素,然后每块分配第二个元素,直至分配完所有元素。Complete 方法
就是每个元素分配一个寄存器存储。如图 20-1 所示:
vivado HLS 优化总结以及相关流程
vivado HLS 优化总结以及相关流程

七、函数层面优化

Inline

对函数的 inline 就是去除了函数的层次化,可以通过 INLINE 这个 directive 来实现。对
函数inlining的好处是可以改善资源消耗,因为inline之后就不再需要调用函数的相关逻辑。
对于一些小函数 Vivado HLS 会自动进行 inlining 处理,可以改善相应的 QoR(quality of
results)。如果不希望对某个函数自动 inline 的话可以通过 INLINE 这个 directive 中的-off 选
项实现。自动 inline 时在综合时的信息输出窗口中可以看到相应的输出信息。 Inlinin 之后
在综合后的 RTL 代码中相应的函数结构就没有了。

Allocation

Allocation 实际上是定义了函数和相应的 RTL module 之间的关系,也就是定义了在 RTL
代码中实现某个具体函数或者操作的实例数量。这个功能可以通过 ALLOCATION 这个
directive 来实现。
Allocation 的主要作用就是使相同函数被多次调用时可以有多个实例,这样可以使之并
行执行,能够改善 latency 并提高吞吐率,但是要占用更多的资源。

Dataflow

Dataflow 在 for 循环优化中用到过,在这里应用于函数。如图 23-1 所示,在默认情况
下,数据相关的函数之间是按顺序执行的,当 Dataflow 之后,顺序处理就变成了并行处理。
函数之间通过 Channel 连接,channel 可以时 ping-pong RAM 也可以是 FIFO。
vivado HLS 优化总结以及相关流程
DATAFLOW 可以作用于顺序执行的一些任务,这些任务可以是函数、循环或者两者都
有,DATAFLOW 就是把顺序处理机制变成了并行处理机制。上图中的 channel 表示后面的
任务并不需要等到前面的任务完全执行完了再执行,而是只需要前面的有数据输出到下一个
任务就可以开始执行了。所以 DATAFLOW 允许任务之间有交叠(overlap),这里的重叠就
是上述的并行处理(parallel process),这种机制可以降低 latency。
vivado HLS 优化总结以及相关流程

八、总结分析

改善吞吐率( Throughput )

常用于改善吞吐率的 directive 有 PIPELINE、ARRAY_PARTITION、UNROLL、DATAFLOW
等。
PIPELINE 可以作用于函数和循环,当作用于循环是有个 option,叫做 rewind,该选项
可以进一步改善吞吐率。
对于数组可以使用 ARRAY_PARTITION 来把数组分割成不同的部分,有 3 种分割方式。
对于循环还可以采用 UNROLL 来优化,这时有个选项 factor 用于控制循环被复制成几
份来并行执行。
DATAFLOW 可以作用于函数和循环,是一种 ping-pong 操作的方式。
可以看出提高吞吐率实际上就是通过提高吞吐率来实现的。
vivado HLS 优化总结以及相关流程

改善时延( Latency)

常用于改善时延的 directives 有 LATENCY、LOOP_MERGE、LOOP_FLATTEN 等。
LATENCY 既可以作用于函数也可作用于循环。
LOOP_MERGE 用于将顺序的 Loop 合并在一起。
LOOP_FLATTEN 用于将嵌套的循环展开为一个大的循环。
vivado HLS 优化总结以及相关流程

改善资源( Area)

常用于改善资源的方法是设置更精确的数据类型和位宽,还有一些 directives,如 INLINE、
ALLOCATE、ARRAY_MAP、ARRAY_RESHAPE、FUNCTION_INSTANTIATE 等。
vivado HLS 优化总结以及相关流程