2017-07-29 60 views
2

我正在使用OpenCl开展我的项目。为了提高我的算法的性能,是否可以管道一个内核?如果一个内核由多个步骤组成,让我们说A,B,C,我希望A在完成它的部分并将它传递给B时接受新数据。我可以在它们之间创建通道,但是我不知道如何执行它详细。如何实现opencl内核管道

我可以在.cl文件中写入A,B,C(3个内核)吗?但如何入列NDRange? 我正在使用Altera SDK进行FPGA HPC开发。 谢谢。

回答

4

流水线可以通过使用几个与通道连接的内核来实现。随着所有内核同时运行,数据从一个转移到另一个:

Pipeline example from Intel FPGA OpenCL SDK Programming Guide

该管道非常简单的例子是:

channel int foo_bar_channel; 
channel float bar_baz_channel; 

__kernel void foo(__global int* in) { 
    for (int i = 0; i < 1024; ++i) { 
    int value = in[i]; 
    value = clamp(value, 0, 255);     // do some work 
    write_channel_altera(foo_bar_channel, value); // send data to the next kernel 
    } 
} 

__kernel void bar() { 
    for (int i = 0; i < 1024; ++i) { 
    int value = read_channel_altera(foo_bar_channel); // take data from foo 
    float fvalue = (float) value; 
    write_channel_altera(bar_baz_channel, value); // send data to the next kernel 
    } 
} 

__kernel void baz(__global int* out) { 
    for (int i = 0; i < 1024; ++i) {n 
    float value = read_channel_altera(bar_baz_channel); 
    float s = sin(value); 
    out[i] = s;         // write result in the end 
    } 
} 

你可以写在一个单一的.CL所有内核文件或使用不同的文件,然后#将它们包括到主.cl文件中。

我们希望我们所有的内核可以同时运行,因此它们可以接受彼此的数据。由于只有有序命令队列支持,我们必须使用不同的队列,每个内核:

cl_queue foo_queue = clCreateCommandQueue(...); 
cl_queue bar_queue = clCreateCommandQueue(...); 
cl_queue baz_queue = clCreateCommandQueue(...); 

clEnqueueTask(foo_queue, foo_kernel); 
clEnqueueTask(bar_queue, bar_kernel); 
clEnqueueTask(baz_queue, baz_kernel); 

clFinish(baz_queue); // last kernel in our pipeline 

不同的OpenCL编程GPU,我们依靠数据流水线,所以NDRange内核不会给我们带来任何好处。使用单个工作项内核而不是NDRange内核,所以我们使用clEnqueueTask函数对它们进行排队。额外的内核属性(reqd_work_group_size)可用于标记单个工作项内核,为编译器提供一些优化空间。

检查有关渠道和内核属性(具体而言,第1.6.4节针对OpenCL渠道推广实施英特尔FPGA SDK)的更多信息,英特尔FPGA SDK针对OpenCL编程指南:

https://www.altera.com/en_US/pdfs/literature/hb/opencl-sdk/aocl_programming_guide.pdf

+0

“通道”似乎是供应商特定的。不是“管道”应该是这样做的方式吗? (我问,不是说;你显然比我更了解FPGA OpenCL)。 – Dithermaster

+0

嗨,非常感谢你回答安德鲁。所以为了让不同的内核同时工作,我需要使用clEnqueueTask来排队我的内核而不是EnqueueNDRange?并且还为我的所有内核分别创建我的内核和命令队列? –

+0

而且编译器会自动管理我的单个内核吗?例如。对于(round = 0; round