我有一个C#项目,其中我从相机中检索灰度图像并使用图像数据进行一些计算。计算非常耗时,因为我需要多次遍历整个图像,而且我在CPU上完成所有操作。
现在我想尝试在GPU上运行评估,但我在实现这一目标方面付出了很多努力,因为我之前从未做过任何GPU计算。
该软件应该能够在具有不同硬件的几台计算机上运行,因此CUDA对我来说不是一个解决方案,因为代码也应该在只有板载图形的笔记本电脑上运行。经过一些研究后,我来到了Cloo(found it on this project),这似乎是一个非常合理的选择。
到目前为止,我已将Cloo集成到我的项目中,并尝试运行this hello world示例。我想它正在运行,因为我没有任何异常,但我不知道在哪里可以看到打印输出。
对于我的计算,我需要将图像传递给GPU,我还需要在计算过程中使用x-y坐标。所以,在C#中,计算看起来像这样:
int a = 0;
for (int y = 0; y < img_height; y++){
for (int x = 0; x < img_width; x++){
a += image[x,y] * x * y;
}
}
int b = 0;
for (int y = 0; y < img_height; y++){
for (int x = 0; x < img_width; x++){
b += image[x,y] * (x-a) * y;
}
}
现在我想让这些计算在GPU上运行,我希望并行y
- 循环,以便在每个任务中运行一个x
循环。然后我可以获取所有结果值并在第二个循环块开始之前添加它们。
之后我想将值a
和b
返回到我的C#代码并在那里使用它们。
所以,结束我的问题:
img_width
,img_height
)传递给GPU的最佳方法是什么?kernel void...
我希望我的问题很清楚,我提供了足够的信息来理解我的挣扎。任何帮助表示赞赏。提前谢谢。
答案 0 :(得分:0)
让我们对问题进行逆向工程。理解image[][], image_height, image_width, a, b
for
- 环的串联性能较差给定定义的代码,可能只有一个循环,因此可以降低开销成本,最好还可以最大化缓存对齐的矢量化代码。
Cache-Naive重新制定:
int a = 0;
int c = 1;
for ( int y = 0; y < img_height; y++ ){
for ( int x = 0; x < img_width; x++ ){
int intermediate = image[x,y] * y; // .SET PROD(i[x,y],y)
a += x * intermediate; // .REUSE 1st
c -= intermediate; // .REUSE 2nd
}
}
int b = a * c; // was my fault upon being in a hurry leaving for weekend :o)
将代码移动到拆分串联循环只会增加这些开销,并在代码性能调整中破坏任何可能的缓存友好技巧。
OpenCL和Cloo记录了这些细节,因此这里不需要任何神奇的方法。
然而,每个此类主机端与设备端+设备端到主机端传输都存在延迟成本。鉴于你声称16bit-1920x1200图像数据要在循环中重新处理 ~10次,这些延迟有可能不需要花费在每个这样的循环传递上。 / p>
最差的性能杀手是非常浅的内核数学密度。问题是,在内核中确实没有多少计算,因此任何有效的SIMD / GPU并行技巧的可能性确实很低。
从这个意义上讲,CPU端的智能矢量化代码将比(H2D + D2H) - 开销 - 远程延迟 - 恶意计算 - 浅层GPU内核处理做得更好。
作为原型并提供额外的缓存友好的矢量化技巧,in-ram + in-cache矢量化代码将有机会击败所有OpenCL和混合GPU / CPU自动ad-hoc内核编译生成的设备代码及其计算工作