在使用高层次综合,创造高质量的RTL设计时,一个重要部分就是对C代码进行优化。 Vivado HLS拥有自动优化的功能,试图最小化loop和function的latency,为了实现这一点,软件会在loop和function上并行执行尽可能多的操作(比如说,在function级别上,高级综合总是试图并行执行function)。 除了这些自动优化,我们可以手动进行程序优化,即用在不同的solution中添加不同的directive的方法,进行优化和性能对比。其中,对同一个工程,可以建立多个不同的solution(解决方案),为不同的solution添加directive可以达到如下目的: 1、并行执行多个tasks,例如,同一个function的多次执行或同一loop的多次迭代。这是流水线结构。 2、调整数组的物理实现((block RAM),函数,循环和端口(I/O),以提高数据的可用性,并帮助数据流更快地通过设计。 3、提供关于数据dependency的信息,或者缺乏数据dependency,允许执行更多的优化。最终的优化是修改C源代码,以消除在代码中意外的dependency,但是这可能会限制硬件的性能。 本文使用的例子是设计一个矩阵相乘函数。目标是在每一个时钟周期处理一个新的sample,并实现数据流接口。一、优化matrix multiplier。1、solution1(无优化) (1)矩阵乘法器设计,来显示如何优化基于loop的设计。设计目标是在每个时钟周期读取一个使用FIFO接口的sample, 同时最大限度地减少面积。此分析包括在loop级优化和在function级优化的方法。
(1)对比loops和function pipeline的使用,创建一个可以处理采样时钟的设计。 (2)分析设计不符合性能要求的两个最常见的原因:loops dependency和数据流的限制(或瓶颈)。 Step 1: 创建并打开Project
找到Design_Optimization lab1文件夹,依次在Command Prompt 窗口输入vivado_hls –f run_hls.tcl和vivado_hls –p matrixmul_prj Step 2: 综合分析设计
综合后的结果:
(1)图中,总的interval为80个时钟周期。因为每个输入数组中都有九个元素,所以设计每输入读取需要约九个周期;
(2)interval比latency多一个时钟周期,所以没有在硬件上并行执行,即无流水;
(3)interval/latency的消耗主要是用于嵌套循环loops(本例有三种循环,每个循环均是迭代三次):
1)Product inner loop:
①有一个2个时钟周期的延迟。
②总的迭代有6个时钟周期。
2)COL loop:
①它需要1个时钟输入和1个时钟退出。
②它需要8个时钟周期为每个迭代(1 + 6 + 1)。
③总的有24个周期完成所有迭代。
3)顶层loops每次迭代需要26个时钟周期,总的loops迭代共78时钟周期。 为了改善initiation interval,则需要加入流水:pipeline loops或pipeline整个function,并比较这两种结果。 当pipelining loops时,loops的initiation interval是监控的重要度量指标。即使设计达到loop可以在每个时钟周期处理一个sample,函数的initiation interval仍然需要包含函数内的loops来完成所有数据的处理。 2、solution2:(Pipeline the Product Loop)Step 1创建solution2,在Product loop下面插入pipeline directive(这里在Directive Editor下选择pipeline) 。
注意:当pipeline嵌套loop时,通过pipeline最内部Loop最大的好处就是,即有利于处理数据的sample。高级综合自动应用loop flattening,折叠嵌套loop,删除loop转换(本质上是创建一个更多迭代的单循环,但时钟周期整体较少)。Step 2 综合设计到RTL级
在综合过程中,我们得到Console pane中报告的信息,显示loop flattening是loop Row上执行,默认内部Interval target为1由于依赖关系不能在loop Product上完成。
图中表明,虽然Product loop已经被pipeline,interval为2,但是顶层loop没有被pipeline。顶层loop不能pipeline的原因是,loop flattening只发生在loop Row,在loop Col 到Product loop上没有loop flattening。(下面解释loop flattening不能flatten所有nested loop的原因)Step 3 打开Analysis窗口,选择state C1的write operation,右击选择Goto Source
状态C1下的写操作是由于代码在Product loop前就已经设置res为0。因为res是在顶层函数,在RTL里这是在写入一个端口:这个操作必须发生在loop Product执行之前。因为它不是一个内部操作,而是会对I / O行为产生影响,这种操作不能移动或优化。这可以阻止Product loop被flatten进入row_col loop。
|