vivado hls移除假性依赖关系以及改善循环流水线化说明
一、移除假性依赖和流水线化说明
1.在vivado hls设计中,如果要实现高效的pipeline流水线设计,
比较重要的一点,是要对假性依赖和真性依赖进行甄别和判断,
如何对其进行正确的处理;
2.HLS工具作为一个高层次工具,为了保证设计的正确性,是不能过于冒进,所以很多设计采取了保守的策略。
这种保守是HLS编译器为了确保用户设计的逻辑的正确性。但是,由于这种保守型的设计,会将很多没有依赖
关系的数据流或者操作,看成了依赖关系,会将一些假性的依赖进行了误判,将假性依赖判断为真性依赖。这将
会影响设计的流水线化,由于存在依赖,会造成II偏大,从而降低了设计的throutput吞吐量
3.吞吐量 (samples/s) = 时钟频率 (Hz) / II;可以看出II=1是设计的目标
4.II=1表示每个clock都运行一个新的数据输入进来;pipeline流水线就是实现II=1的手段;也就是说II是目标,pipeline是手段和方式
5.如果将假性依赖判断为真性依赖,那么九影响设计的pipeline设计了,所以设计中需要对真假依赖进行优化设计。
二、依赖的几个概念
1.真依赖 (True/Flow Dependency)
后续操作必须等待前面操作的结果,这是无法规避的。这种情况就是前后操作或者处理之间是有先后顺序的,也就是操作是顺序执行的,
这个时候你就不能将依赖去掉,否则你过度进行优化,会造成逻辑错误。那么,在这种情况下,你将不能使用去依赖program指令进行
指导HLS工具去优化你的设计了,这个时候,你唯一能做的是修改你的代码框架和结构,或者改变代码的实现方式,来改变这种依赖的等效关系,
从而来提高设计的性能。如果你没有办法改变这个真的依赖关系,那么你就只能维持当前的设计了。
2.假性依赖 (False Dependency)
包括反依赖 (WAR) 和输出依赖 (WAW)。它们并非由数据流必需性引起,而是由于存储位置(变量)被复用造成的,可以消除。
反依赖 (WAR) 和输出依赖 (WAW)是否能够移除,也需要对代码进行分析和改写设计,并不是说这两种模式下的设计全部可以去掉依赖,
而是说很多这种依赖模型下的依赖都是假的,看起来是有依赖关系的,实际上仔细想下,是没有依赖关系的,但是HLS工具没有那么智能化,
也不是说没有那么智能化吧,主要还是太保守,造成HLS工具睁一只眼闭一只眼,不管这事儿,直接当有依赖关系处理了。这个时候,你就
需要明确的告诉HLS编译器,告诉它,这个是没有依赖关系的,你大胆的优化,不要保守了。这个时候HLS工具就比较冒进的进行优化设计了。
3.流水线中的依赖
通常分为同一迭代内的依赖(intra)和跨迭代的依赖(inter),后者是流水线优化的主要障碍。
关于同一迭代内的依赖就是同层for循环中前后两个操作存在依赖关系
关于跨迭代的依赖(inter)就是for循环的第一次迭代和第二次迭代存在依赖关系,第二次迭代和第三次迭代存在依赖关系。
三、假性依赖出现的时机
1.变量/数组复用 (Resource Reuse):在循环的不同迭代中,重复使用同一个标量变量或数组的不同元素。编译器可能因无法精确分析索引而误判为同一个存储位置的竞争访问-2。
2.静态变量 (Static Variables):static变量会跨迭代保持其值,这天然构成了跨迭代的真依赖,会阻止流水线启动。
3.复杂或重叠的内存访问模式:编译器难以静态证明的、复杂的指针或数组索引模式
四、消除假性依赖的方法
1.修改用户设计代码,进行Code Refactoring代码重构
代码重构的方式是从根本上解决假性依赖问题,也是最推荐的方式。
代码重构改进假性依赖的可行性操作有:
variable renaming,也就是变量的重新命名,变量重命名 (Variable Renaming):当循环中一个变量在不同阶段被赋予新值,导致输出依赖 (WAW) 时,可以为每次写操作引入新的临时变量,消除复用
拆分读写逻辑:将复杂的读写操作拆解为更简单的步骤,帮助编译器清晰地看到操作的独立性
将静态变量改为局部变量:用局部变量在循环内计算,在循环外更新 static 变量,将跨迭代依赖转化为一次性的外部更新
指针受限 (Pointer Restriction):在C/C++函数参数中使用 restrict 关键字,向编译器保证指针所指向的内存区域是独立、不重叠的
2.数组分割 (Array Partitioning)
3.DEPENDENCE 编译指令 (The Last Resort)
当前两种方法无效时,可以使用 #pragma HLS DEPENDENCE 指令直接告诉编译器忽略某个假性依赖。但使用此方法需要谨慎,因为错误地忽略真依赖会导致硬件功能错误-。
指令格式:
#pragma HLS DEPENDENCE variable=<var> <inter/intra> <RAW/WAR/WAW> <true/false>
参数说明:
variable:指定存在依赖的变量名。
inter / intra:inter 指循环不同迭代间的依赖,intra 指同一迭代内的依赖。
RAW / WAR / WAW:可选参数,精确指定要忽略的依赖类型。
true / false:true 表示强制工具考虑依赖,false 表示移除(忽略)该假性依赖。
