本节主要介绍的是《跟Xilinx SAE 学HLS系列视频讲座》第15,16,17,18,19节。 跟Xilinx SAE 学HLS系列视频讲座笔记(1) 跟Xilinx SAE 学HLS系列视频讲座笔记(2)—— 编写高效的C Test Bench 跟Xilinx SAE 学HLS系列视频讲座笔记(3)—— 接口综合 跟Xilinx SAE 学HLS系列视频讲座笔记(4)—— For循环优化 跟Xilinx SAE 学HLS系列视频讲座笔记(5)—— 数组优化 跟Xilinx SAE 学HLS系列视频讲座笔记(6)—— 函数优化
本节主要讲解为:
与for循环相关的基本概念Pipelining的for循环for循环的展开for循环的循环变量的数据类型,是否对综合后结果的资源有所影响。1. 衡量指标 loop trip count :循环执行了几次 loop interation latency :循环一次用了几个cycle loop interation latency(Loop II) :两次循环直接间隔了几个cycle loop latency:整个for循环的latency function latency function initial interval(II) 2. 流水线优化
设置比较简单 采用Pipeline前后对比我们可以发现,在不采用流水线的时候是过程化运行(有时间的先后顺序进行);当采用流水线后,当在读数据的时候,下一个Fou循环就开始读地址,会有并行(椭圆标记的位置)的效果。 3. For循环展开
默认情况下,C函数中的For循环是被折叠的,即每次循环均采用同一套电路,它是分时复用的;所谓的展开是复制了多个相同的电路,从而允许所有迭代并行发生。 我们也可以把For循环部分展开,如下例所示,将For循环拆解成了3部分,被复制后(0,3),(1,4)和(2,5)分别共用一套逻辑资源。 4. i的数据类型
通常情况下i的数据类型是不会对资源的分配产生影响。 如下例子,Vivado HLS考虑到迭代次数被限制为6次,并为每个列出的数据类型使用最少的FPGA资源。因此,每种数据类型对资源使用情况都相同。 5. 总结
清楚地了解Il和loop/function latencyPipelining是减少循环延迟的一种非常流行的方法展开允许循环主体并行运行部分展开可以在并行性和资源之间进行折中迭代类型不影响面积结果循环变量的数据类型,对最终的资源消耗量没有影响。1. 例子引入
这个例子有两个for循环,这两个for循环分别执行的是加法和减法。他们是可以并行执行的,我们所期望的计算方式为图右所示。 但实际的的处理方式,是按顺序执行的,所以latency就会比较的长,这不符号我们预期的结果。 在Vivado HLS提供了一种方式,将for循环进行合并,我们也因此引入了一个新的概念叫做region(下图绿线框对应的部分),这样循环合并部分就是region这一部分。 合并之后
由此我们可以得出合并可以在某种程度上帮助减少延迟。
2. 循环边界为不同的常数
如果循环界限是不同常量,则将最大常数值用作合并循环的界限。 3. 变量边界和常数边界 在没有合并时候,我们会发现Trip Count为0~15,这是因为k的变量类型为ap_uint<4>,其数据上限位15。当我们实施循环合并时会报错(无法合并)。这说明变量边界和常数边界无法合并。
4. 循环边界均为变量
当我们实施合并循环也会产生错误信息 我们可以通过修改代码去解决。 5. 循环合并规则
情况合并结果固定常数将最大常数值用作合并循环的边界均为变量不能进行直接合并,可以通过更改代码去解决(保证边界大小相同)一个常数一个变量没有办法合并6. 总结
1. 例子引入
这个例子有3个循环,分别是Task A,Task B和Task C,数据流如图右所示,可以发现Task B依赖于Task A,Task C依赖于Task B。我们可以采取什么措施来减少延迟?我们可以采用Pipeline,for循环的合并是不可以的。 2. Dataflow for 'For-Loop’
在没有使用Dataflow时,三者执行顺序为A—>B—>C,没有交叠。使用Dataflow后,我们在三个循环之间加入channel(Ping-pong RAM,FIFO或Register),通道可确保不需要任务等待上一个任务完成所有操作才可以开始,此时循环之间是一个并行的关系,三者之间是有交叠的,这可以减少延迟提高数据的吞吐量。 性能展示
注:默认情况下,通道是通过ping-pong RAM实现的。通过conifg_dataflow,可以将实现方法更改为FIFO。
3. Dataflow优化限制
以下代码样式使Vivado HLS无法执行DATAFLOW优化
Single-producer-consumer violationsBypassing tasksFeedback between tasksConditional execution of tasksLoop scopes with variable boundsLoops with multiple exit conditions我们如何进行优化使他可以使用
Bypassing Tasks Model 我们如何进行优化使他可以使用
4. Configuring Dataflow Memory Channels
Vivado HLS根据数据producer和consumer 的访问方式,将任务之间的通道实现为ping-pong或FIFO buffers。
对于标量,指针和 reference parameters以及函数返回,Vivado HLS将通道实现为FIFO。如果参数(producer和consumer )是一个数组,则Vivado HLS将该通道实现为一个ping-pong buffers或FIFO,如下所示 如果Vivado HLS确定按顺序访问数据,则Vivado HLS将存储通道实现为深度为1的FIFO通道.如果Vivado HLS无法确定数据是按顺序访问的,或者无法确定数据是以任意方式访问的,则Vivado HLS将内存通道实现为ping-pong buffers。5. 明确指定默认通道
使用config_dataflow配置
此配置为设计中的所有通道设置默认通道。要减少通道中使用的内存大小,可以使用FIFO。要显式设置FIFO中元素的深度或数量,请使用fifo_depth选项。6. 总结
1. 三种分类 2. A Simple Example of Perfect Loop
矩阵对应元素相乘,我们对内部for循环做Pipeline和对外部for循环做Pipeline的情况对比,如下。
Pipeline最里面for循环可为大多数应用使用更少的硬件资源(与外部for循环相比),并具有通常可接受的吞吐量。对层次结构的高层进行Pipeline,会展开所有子循环,并可以创建更多要调度的操作(这可能会影响运行时间和内存容量),但通常在吞吐量和延迟方面提供最高性能的设计。本节主要讲解为:
有关循环并行性的问题for循环做流水如何使用rewindfor循环的边界是变量时,如何处理1. 并行性
默认情况下,Vivado HLS对for循环做顺序执行的。虽然合并这些循环可以减少等待时间,但有时循环边界是变量和常数,因此无法合并循环。 因为这两个for循环是独立存在的,我们可以定义一个函数并且调用两次,但是在默认情况下,HLS尝试通过多次使用该功能来节省资源,而不是通过并行运行两个副本来节省时间。因此结果与上文情况相同。 我们可以采用ALLOCATION使这两个副本并行运行,从而减少延迟性,配置与结果如下图所示。 2. Loop Pipeline with Rewind Option 当函数中有多个循环时候,我们做Rewind,会爆出警告,没有办法执行,所以我们可以看出Rewind不是所用的for循环都是适用的。
如何对for循环自动添加流水
config_compile配置使循环可以根据迭代计数自动进行Pipeline处理。
pipeline_loops选项设置迭代限制迭代次数低于此限制的所有循环将自动Pipeline默认为0:不执行自动Pipeline的循环如果设计中有不想使用自动自动Pipeline的循环,则将带有off选项的PIPELINE指令应用于该循环。off选项可防止自动循环流水线。 Addressing Failure to Pipeline
当任务Pipeline时,层次结构中的所有循环都会自动展开
这是进行Pipeline处理的要求如果循环具有变量边界,则无法展开该循环,这将防止任务被Pipeline,因为Vivado HLS无法知道循环何时完成3. Variable Loop Bounds
当循环的边界为变量的时候,Vivado HLS将不能够确定的知道延迟为多少(报告为问号"?"),即设计性能未知。 对于这种情形我们有三种处理方式。
使用Tripcount指令将循环边界的数据类型声明为ap_int <w>在C代码中使用assert macroTripcount指令
Tripcount指令对综合结果没有影响,仅对报告有影响,可以比较来自不同解决方案的报告。
数据类型声明为ap_int <w>
在C代码中使用assert macro
对三种做对比 我们可以发现第三种方法的效果是最好的
4. 总结