【发布时间】:2016-09-26 11:27:34
【问题描述】:
我有以下 opencl 核函数来获取图像的列总和。
__kernel void columnSum(__global float* src,__global float* dst,int srcCols,
int srcRows,int srcStep,int dstStep)
{
const int x = get_global_id(0);
srcStep >>= 2;
dstStep >>= 2;
if (x < srcCols)
{
int srcIdx = x ;
int dstIdx = x ;
float sum = 0;
for (int y = 0; y < srcRows; ++y)
{
sum += src[srcIdx];
dst[dstIdx] = sum;
srcIdx += srcStep;
dstIdx += dstStep;
}
}
}
这里我指定每个线程处理一列,这样很多线程可以并行获取每一列的column_sum。
我还用float4重写了上面的内核,这样每个线程可以从源图像中一次读取一行4个元素,如下图。
__kernel void columnSum(__global float* src,__global float* dst,int srcCols,
int srcRows,int srcStep,int dstStep)
{
const int x = get_global_id(0);
srcStep >>= 2;
dstStep >>= 2;
if (x < srcCols/4)
{
int srcIdx = x ;
int dstIdx = x ;
float4 sum = (float4)(0.0f, 0.0f, 0.0f, 0.0f);
for (int y = 0; y < srcRows; ++y)
{
float4 temp2;
temp2 = vload4(0, &src[4 * srcIdx]);
sum = sum + temp2;
vstore4(sum, 0, &dst[4 * dstIdx]);
srcIdx += (srcStep/4);
dstIdx += (dstStep/4);
}
}
}
在这种情况下,理论上,我认为第二个内核处理图像所消耗的时间应该是第一个内核函数所消耗时间的1/4。但是,无论图像有多大,两个内核几乎消耗相同的时间。我不知道为什么。你们能给我一些想法吗? T
【问题讨论】:
-
那么瓶颈不在于信息共享部分。除了你没有得到 1/4 的加速之外,性能是否可以接受?我问这个看看你是否可能有一些同步问题。您执行多少计算?简单的总结只是一个例子?
-
您知道 SIMD 指令,对吧?它们可以同时对 2、4、8 或 16 个(或更多,取决于硬件)值执行相同的操作。这可能是时间相同的原因,因为它有效地完成了相同数量的工作,但使用的是 SIMD 指令。这在 GPU 中非常普遍,但在 CPU 上也可以观察到较小程度。 4 个浮点数对 SSE 寄存器有好处,听起来差不多。正如 Csaba 指出的那样,你也可能会成为内存传输的瓶颈。
-
嗯,我使用 float4 的原因是这样的:假设我们有 256 个线程可以同时运行。我们有一个 1024*1024 的图像。如果我们使用第一个内核,则 256 个线程首先处理前 256 列,然后处理接下来的 256 列,以此类推,直到所有列都处理完毕。在这种情况下,将消耗 4*t,其中 t 代表 256 个线程处理 256 列所消耗的时间。但是,如果我们使用第二个内核,由于每个线程处理图像的一行中的 4 个元素,所以256个线程可以处理1024列,时间为t。这只是一个估计。 @托马斯
-
我的意思是,在具有足够宽 SIMD 寄存器的硬件上,添加/乘以两个 float4 需要与添加/乘以两个浮点数相同的时间。因此,从这个意义上说,两个内核花费大约相同的时间这一事实应该不足为奇。
-
我不知道我的估计是否正确。实际上,我将 float4 用于我编写的另一个内核,它实际上实现了一些加速。所以我为这篇文章中提到的内核尝试了 float4。但我无法获得任何加速。
标签: opencl