如何减少OpenCL内核之间的代码重复?

如何减少OpenCL内核之间的代码重复?,opencl,code-duplication,Opencl,Code Duplication,我有几个类似的内核来生成随机数据并将其存储在全局内存中。我总是使用相同的算法进行随机化,但由于可变范围的问题(我需要跟踪数据),我无法避免严重的代码重复 有没有办法避免这种情况?在OpenCL中生成随机数据似乎是一项相当标准的任务,但具有这种级别的代码重复违背了任何良好的编码标准。例如,下面是我的两个内核: //////////////////////////////////////////////////////////////////////////////// // OpenCL Kern

我有几个类似的内核来生成随机数据并将其存储在全局内存中。我总是使用相同的算法进行随机化,但由于可变范围的问题(我需要跟踪数据),我无法避免严重的代码重复

有没有办法避免这种情况?在OpenCL中生成随机数据似乎是一项相当标准的任务,但具有这种级别的代码重复违背了任何良好的编码标准。例如,下面是我的两个内核:

////////////////////////////////////////////////////////////////////////////////
// OpenCL Kernel for Mersenne Twister RNG -- applied to AWGN channel
////////////////////////////////////////////////////////////////////////////////
__kernel void MersenneTwisterAWGN(__global double* d_Rand, 
                  __global int* seeds,
                              __global long* inputcw,
                  int nPerRng, float sigma)
{
    int globalID = get_global_id(0);
    double c = 2.0/(sigma*sigma);

    int iState, iState1, iStateM, iOut;
    unsigned int mti, mti1, mtiM, x;
    unsigned int mt[MT_NN]; 

    //Initialize current state
    mt[0] = seeds[globalID];
    for (iState = 1; iState < MT_NN; iState++)
        mt[iState] = (1812433253U*(mt[iState-1]^(mt[iState-1]>>30))+iState) & MT_WMASK;

    iState = 0;
    mti1 = mt[0];
    for (iOut = 0; iOut < nPerRng; iOut=iOut+2) {
        iState1 = iState + 1;
        iStateM = iState + MT_MM;
        if(iState1 >= MT_NN) iState1 -= MT_NN;
        if(iStateM >= MT_NN) iStateM -= MT_NN;
        mti  = mti1;
        mti1 = mt[iState1];
        mtiM = mt[iStateM];

        // MT recurrence
        x = (mti & MT_UMASK) | (mti1 & MT_LMASK);
        x = mtiM ^ (x >> 1) ^ ((x & 1) ? matrix_a : 0);

        mt[iState] = x;
        iState = iState1;

        //Tempering transformation
        x ^= (x >> MT_SHIFT0);
        x ^= (x << MT_SHIFTB) & mask_b;
        x ^= (x << MT_SHIFTC) & mask_c;
        x ^= (x >> MT_SHIFT1);

        double u1 = ((double)x + 1.0f) / 4294967296.0f;

        iState1 = iState + 1;
        iStateM = iState + MT_MM;
        if(iState1 >= MT_NN) iState1 -= MT_NN;
        if(iStateM >= MT_NN) iStateM -= MT_NN;
        mti  = mti1;
        mti1 = mt[iState1];
        mtiM = mt[iStateM];

        // MT recurrence
        x = (mti & MT_UMASK) | (mti1 & MT_LMASK);
        x = mtiM ^ (x >> 1) ^ ((x & 1) ? matrix_a : 0);

        mt[iState] = x;
        iState = iState1;

        //Tempering transformation
        x ^= (x >> MT_SHIFT0);
        x ^= (x << MT_SHIFTB) & mask_b;
        x ^= (x << MT_SHIFTC) & mask_c;
        x ^= (x >> MT_SHIFT1);

        double u2 = ((double)x + 1.0f) / 4294967296.0f;

        double r = sqrt(-2.0f * log(u1));
        double phi = 2 * PI * u2;

        u1 = r * cos(phi);
        u1 = inputcw[iOut]+sigma*u1;
        u1=1/(1+exp(-c*u1));
        d_Rand[globalID * nPerRng + iOut]=log((1-u1)/u1);
        if (iOut!=nPerRng-1) {
            u2 = r * sin(phi);
            u2 = inputcw[iOut+1]+sigma*u2;
            u2=1/(1+exp(-c*u2));
            u2=log((1-u2)/u2);
            d_Rand[globalID * nPerRng + iOut+1]=u2;
        }
    }
}
////////////////////////////////////////////////////////////////////////////////
//Mersenne Twister RNG的OpenCL内核——应用于AWGN信道
////////////////////////////////////////////////////////////////////////////////
__内核无效MersenneTwisterAWGN(uu全局双*d_urand,
__全球整数*种子,
__全局长*输入cw,
int nPerRng,浮点西格玛)
{
int globalID=get_global_id(0);
双c=2.0/(西格玛*西格玛);
int iState、iState1、iStateM、iOut;
无符号整数mti,mti1,mtiM,x;
无符号整数mt[mt_NN];
//初始化当前状态
mt[0]=种子[globalID];
对于(iState=1;iState>30))+iState)和mt_WMASK;
iState=0;
mti1=mt[0];
对于(iOut=0;iOut=MT_NN)iState1-=MT_NN;
如果(iStateM>=MT_NN)iStateM-=MT_NN;
mti=mti1;
mti1=mt[iState1];
mtiM=mt[iStateM];
//MT复发
x=(mti和MT|UMASK)|(mti1和MT|LMASK);
x=mtiM^(x>>1)^((x&1)矩阵a:0);
mt[iState]=x;
iState=iState1;
//回火转变
x^=(x>>移动);
x^=(x MT_SHIFT1);
双u1=((双)x+1.0f)/4294967296.0f;
iState1=iState+1;
iState=iState+MT_MM;
如果(iState1>=MT_NN)iState1-=MT_NN;
如果(iStateM>=MT_NN)iStateM-=MT_NN;
mti=mti1;
mti1=mt[iState1];
mtiM=mt[iStateM];
//MT复发
x=(mti和MT|UMASK)|(mti1和MT|LMASK);
x=mtiM^(x>>1)^((x&1)矩阵a:0);
mt[iState]=x;
iState=iState1;
//回火转变
x^=(x>>移动);
x^=(x MT_SHIFT1);
双u2=((双)x+1.0f)/4294967296.0f;
双r=sqrt(-2.0f*log(u1));
双φ=2*PI*u2;
u1=r*cos(φ);
u1=输入CW[iOut]+西格玛*u1;
u1=1/(1+exp(-c*u1));
d_Rand[globalID*nPerRng+iOut]=log((1-u1)/u1);
如果(iOut!=nPerRng-1){
u2=r*sin(φ);
u2=输入CW[iOut+1]+西格玛*u2;
u2=1/(1+exp(-c*u2));
u2=对数((1-u2)/u2);
d_Rand[globalID*nPerRng+iOut+1]=u2;
}
}
}

////////////////////////////////////////////////////////////////////////////////
//Mersenne Twister RNG的OpenCL内核——应用于BSC信道
////////////////////////////////////////////////////////////////////////////////
__内核无效MersenneTwisterBSC(uu全局双*d_urand,
__全球整数*种子,
__全局长*输入cw,
int nPerRng,float fliprob)
{
int globalID=get_global_id(0);
int iState、iState1、iStateM、iOut;
无符号整数mti,mti1,mtiM,x;
无符号整数mt[mt_NN];
//初始化当前状态
mt[0]=种子[globalID];
对于(iState=1;iState>30))+iState)和mt_WMASK;
iState=0;
mti1=mt[0];
对于(iOut=0;iOut=MT_NN)iState1-=MT_NN;
如果(iStateM>=MT_NN)iStateM-=MT_NN;
mti=mti1;
mti1=mt[iState1];
mtiM=mt[iStateM];
//MT复发
x=(mti和MT|UMASK)|(mti1和MT|LMASK);
x=mtiM^(x>>1)^((x&1)矩阵a:0);
mt[iState]=x;
iState=iState1;
//回火转变
x^=(x>>移动);
x^=(x MT_SHIFT1);
双c=对数((1-fliprob)/fliprob);
双u=((双)x+1.0f)/4294967296.0f;
u=(2*无岛(u,fliprob)-1)*输入cw[iOut]*c;
d_Rand[globalID*nPerRng+iOut]=u;
}
}
有什么方法、技巧或方法可以避免这种情况吗?子例程似乎无法正确使用变量(尤其是
mt
),因此我没有设法以其他语言允许的方式减少它


还是我应该接受这一点作为OpenCL中的一个必要缺陷,并继续以这种方式管理10个不同的内核?

在Khronos的网站上,它说

OpenCL程序还可能包含辅助函数和可由_内核函数使用的常量数据

每个线程生成0.0f到1.0f之间的随机数的示例:

迭代种子的核心函数:

uint wang_hash(uint seed)
{
   seed = (seed ^ 61) ^ (seed >> 16);
   seed *= 9;
   seed = seed ^ (seed >> 4);
   seed *= 0x27d4eb2d;
   seed = seed ^ (seed >> 15);
   return seed;
}
每个线程种子的初始化和迭代:

// id=thread id, rnd=seed array
void wang_rnd_init(__global unsigned int * rnd,int id)                
{
     uint maxint=0;
     maxint--;  // could be a 0xFFFFFFFF
     uint rndint=wang_hash(id);
     rnd[id]=rndint;
}

// id=thread id, rnd=seed array
float wang_rnd(__global unsigned int * rnd,int id)                
{
     uint maxint=0;
     maxint--;  // could be a 0xFFFFFFFF
     uint rndint=wang_hash(rnd[id]);
     rnd[id]=rndint;
     return ((float)rndint)/(float)maxint;
}
在随机灰度彩色像素生成器内核中的用法:

__kernel void rnd_1(__global unsigned int * rnd, __global int *rgba)
{
      int id=get_global_id(0);
      float rgba_register=wang_rnd(rnd,id);
      rgba[id] = ((int)(rgba_register * 255) << 24) | ((int)(rgba_register * 255) << 16) | ((int)(rgba_register * 255) << 8) | ((int)(rgba_register * 255));
}
\uuuuu内核无效rnd\u1(\uuuu全局无符号int*rnd,\uuuu全局int*rgba)
{
int id=获取全局id(0);
浮点rgba_寄存器=wang_rnd(rnd,id);

rgba[id]=((int)(rgba_register*255)啊哈,是的,这很有意义。现在所有的工作代码都减少了80%。谢谢!另外,如果您有多设备设置,您需要在所有设备上编译它,即使它们在相同的上下文中。
__kernel void rnd_1(__global unsigned int * rnd, __global int *rgba)
{
      int id=get_global_id(0);
      float rgba_register=wang_rnd(rnd,id);
      rgba[id] = ((int)(rgba_register * 255) << 24) | ((int)(rgba_register * 255) << 16) | ((int)(rgba_register * 255) << 8) | ((int)(rgba_register * 255));
}