我在OpenCL中有一个代码,它从给定的点开始逐步减少数组的元素。
这是代码 - rp
是源数组,out
是输出数组:
__kernel void subFilter(__global unsigned char* rp,__global unsigned char *out,int istop,int bpp)
{
int gid = get_global_id(0);//add the offset by bpp to access the next gid
int i;
unsigned char temp=0;
if(gid>=bpp){
i=gid;
while(i>=0)
{
if((temp + rp[i])>255)
{
temp = temp - 256;
temp=temp + rp[i];
}
else
{
temp=temp+rp[i];
}
i=i-bpp;
}
out[gid]=(temp & 0xff); //masked
//rp[gid]=66;
}
else if(gid<bpp)
out[gid]=rp[gid];
}
现在这个工作正常但是比在CPU上运行的相同代码花费更多时间。如果循环被移除,也许会更快? 执行时,它的工作原理如下:
rp[0] = rp[0]; // same for rp[1],rp[2],rp[3]
rp[4] = rp[4]+rp[4-4] // steps of 4 till zero
// ...
rp[16]= rp[16]+rp[12]+rp[8]+rp[4]+rp[0]; // etc.
结果rp[i]
保存在代码中的temp中,最后保存在out[gid]
中
因此,要添加此序列,需要循环,并且需要大量时间...
如果有某种方式,可以缓存前面的总和或者可以完全删除循环,那就太棒了。
如何改进此代码以摆脱循环?
答案 0 :(得分:0)
首先,我建议你摆脱可能的uchar溢出:
__kernel void subFilter(
__global unsigned char *rp,
__global unsigned char *out,
int istop,
int bpp)
{
int gid = get_global_id(0), i = gid;
unsigned char temp = 0;
if(gid>=bpp){
i=gid;
while(i>=0)
{
if(temp > 255 - rp[i])
{
temp -= 255 - rp[i];
}
else
{
temp += rp[i];
}
i -= bpp;
}
//masked
out[gid]=(temp & 0xff);
}
else if(gid<bpp){
out[gid]=rp[gid];
}
}
回到过滤算法。每个工作项都有唯一的ID,用作循环计数器。通常情况下,这是不好的,因为不同的指令集应用于相同的数据,这违反了SIMD的意识形态。可能,这导致线程分歧和表现下降。你的算法的本质是什么?详细描述。可能是,GPU-amenable实现存在。
答案 1 :(得分:0)
消除循环内的条件代码可能会提高性能:
__kernel void subFilter(__global unsigned char* rp,__global unsigned char *out,int istop,int bpp)
{
int gid = get_global_id(0);//add the offset by bpp to access the next gid
int i;
unsigned char temp=0;
out[gid]=rp[gid];
if(gid>=bpp){
i=gid;
while(i>=0)
{
temp+=rp[i];
i-=bpp;
}
out[gid]=(temp & 0xff); //masked
}
}