打开Cl.I只需要将代码转换为使用for循环中的两个工作项。目前它使用一个

时间:2012-10-21 10:38:31

标签: opencl

spmv_csr_scalar_kernel(const int num_rows,
                       const int * ptr,
                       const int * indices,
                       const float * data,
                       const float * x,
                       float * y )
{
    int row = get_global_id(0);
    if(row < num_rows)
    {
        float dot = 0;
        int row_start = ptr[row];
        int row_end = ptr[row+1];
        for (int jj = row_start; jj < row_end; jj++)
        {  
            dot += data[jj] * x[indices[jj]];
        }
        y[row] += dot;
    }
}

上面是用于将CSR格式的稀疏矩阵与列向量相乘的Open Cl代码。它为每个循环使用一个全局工作项。任何人都可以帮助我在每个循环中使用两个工作项。我是新手如果我修改最小的东西,打开cl并得到很多问题。请帮助我。这是我的项目的一部分。我使它平行但我想让它更平行。如果你能帮助我.plzzzz

单个工作项执行从row_start到row_end的for循环。我想将此行或for循环进一步分为两个部分,每个部分由一个工作项执行。我如何继续完成?

这是我能想到的,但它返回了错误的输出。

__kernel void mykernel(__global int* colvector,
                       __global int* val,
                       __global int* result,
                       __global int* index,
                       __global int* rowptr,
                       __global int* sync )
{
    __global int vals[8]={0,0,0,0,0,0,0,0};
    for(int i=0;i<4;i++)
    {
        result[i]=0;
    }
    barrier(CLK_GLOBAL_MEM_FENCE);

    int thread_id=get_global_id(0);
    int warp_id=thread_id/2;
    int lane=(thread_id)&1;
    int row=warp_id;

    if(row<4)
    {
        int row_start = rowptr[row];
        int row_end = rowptr[row+1];
        vals[thread_id]=0;

        for (int i = row_start+lane; i<row_end; i+=2)
        {
            vals[thread_id]+=val[i]*colvector[index[i]];
        }

        vals[thread_id]+=vals[thread_id+1];

        if(lane==0)
        {
            result[row] += vals[thread_id];
        }
    }               
}

1 个答案:

答案 0 :(得分:0)

您需要使用工作组数量和组ID来实现此目的。

spmv_csr_scalar_kernel(const int num_rows, const int * ptr, const int * indices, const float * data, const float * x, float * y) {

    __local float[64] dot; //local memory for dot product. assumes you want to use up to 64-item workgroups.
    int localId = get_local_id(0); //offest value for jj loop
    int localSize = get_local_size(0); //this is the number of work items computing the jj loop
    int nGroups = get_num_groups(0); //number of workgroups executing this kernel

    for (int row = get_group_id(0); row < num_rows; row += nGroups) {
        dot[localId] = 0;
        int row_start = ptr[row] + localId;
        int row_end = ptr[row + 1];
        for (int jj = row_start; jj < row_end; jj++) {
            dot[localId] += data[jj] * x[indices[jj]];
        }
        barrier(CLK_LOCAL_MEM_FENCE);

        //here's where work item #0 in the group sums the values stored in local memory
        if (localId == 0) {
            for (int i = 1; i < localSize; i++) {
                dot[0] += dot[i];
            }
            y[row] += dot[0]; //only a single write to the global memory location
            barrier(CLK_LOCAL_MEM_FENCE);
        }
    }

此内核将使用您想要完成所有工作的任意数量的工作组。 (即组可以在多行上工作)这是通过将'if(row&lt; num_rows)'转换为'for(int row ...'循环来完成的。你可能会发现一个具有正确数量的工作组工作项目可能胜过许多小型工作组。

我使用64作为本地内存大小的硬编码值。上面的内核可以正常工作,最大工作组大小为64. 64在当今的许多设备上都是最佳的。您可以尝试其他硬编码值,或通过传入__local参数来分配本地内存。