为了举例说明,我有一个循环,其中数组的内容在每次迭代中读取和写入一个循环。
int my_array[10] = ...;
for(i=0; i<10; i++) {
if(i<5) {
my_array[i*2] = func_b(my_array[i*2]);//func_b takes double the time of func_a, but it also runs on 1/2 of the time.
}
func_a(myarray[i]);//func_a is executed quickly
}
仅在i=0
上访问相同的元素进行读/写操作,具有适当的延迟,同步算法应允许并行化。我正在努力寻找合适的HLS pragma来迫使它们像一样并行运行
//#pragma HLS to delay by two cycles
for(i=0; i<10; i++) {
func_a(my_array[i]);
}
//#pragma HLS to allow to run each iteration in parallel with the first loop, if possible in two cycles
for(i=0; i<5; i++) {
my_array[i*2] = func_b(my_array[i]);//func_b might be split into two halves for each to fit into one cycle.
}
理想情况下,第一个循环应该在第二个循环完成后完成两个循环,并以这种方式读取最后一个my_array
元素的正确值。我可能有一个误解,但我希望以这种方式(跨两个周期(划分工作,应该提高时钟速度吗?
生成的Verilog代码的其余部分很好,尽管它足够神秘,我宁愿使用C,也不愿尝试修改生成的HDL。关于如何并行化或者是否可行,有什么建议吗?
首先要注意的是,时钟速度不必受循环是否并行运行的影响。可能会改进的是算法的延迟,即运行它所需的周期的总量。
两个函数在同一个循环中都处理了一些元素。因此,除非你重写函数(也许把它们合并在一起(,否则你就有一个无法打破的数据依赖关系(否则你的算法就会失败(。检查您正在访问的索引,并检查操作顺序是否保持不变:
for(int i = 0; i < 10; i++) {
if (i < 5) {
// Accessing indexes: 0, 2, 4, 6, 8
my_array[i * 2] = func_b(my_array[i * 2]);
}
// Accessing indexes: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
func_a(myarray[i]);
}
您提出的解决方案,即第二个代码片段,将不起作用,因为它没有按照与第一个代码片段相同的顺序执行相同的操作(如果您只是运行C/C++代码,则这必须是有效的,它必须具有相同的结果(。
然而,有一件事你可以尝试放一个DATAFLOW杂注,就像这样:
#pragma HLS DATAFLOW
for(i = 0; i < 5; i++) {
my_array[i * 2] = func_b(my_array[i * 2]);
}
for(i = 0; i < 10; i++) {
func_a(my_array[i]);
}
但我不确定HLS是否能正确处理my_array
缓冲区,因为它将由两个循环/进程共享。
我必须完全允许DATAFLOW的最后一个想法是,通过创建生产者-消费者算法,将my_array
拆分为两个不同的缓冲区,算法的每个部分(i
偶数或奇数(一个缓冲区,如下所示:
int my_array_evens[5] = ...;
int my_array_odds[5] = ...;
#pragma HLS DATAFLOW
for(i = 0; i < 5; i++) {
my_array_evens[i * 2] = func_b(my_array_evens[i * 2]); // Dataflow producer
}
for(i = 0; i < 10; i++) {
if (i % 2 == 0) {
func_a(my_array_evens[i]); // Dataflow consumer
} else {
func_a(my_array_odds[i]);
}
}
注意:如果函数相对较小,请在循环中添加PIPELINE杂注以"加快"速度。