【问题标题】:Passing struct to GPU with OpenCL that contains an array of floats使用包含浮点数组的 OpenCL 将结构传递给 GPU
【发布时间】:2013-03-16 08:58:33
【问题描述】:

我目前有一些数据想传递给我的 GPU 并将其乘以 2。

我创建了一个结构,可以在这里看到:

struct GPUPatternData
{
    cl_int nInput,nOutput,patternCount, offest;
    cl_float* patterns;
};

这个结构应该包含一个浮点数组。浮点数数组直到运行时才知道,因为它是由用户指定的。

主机代码:

typedef struct GPUPatternDataContatiner
{

    int nodeInput,nodeOutput,patternCount, offest;
    float* patterns;
} GPUPatternData; 
__kernel void patternDataAddition(__global GPUPatternData* gpd,__global GPUPatternData* output)
{
    int index = get_global_id(0);
    if(index < gpd->patternCount)
    {
        output.patterns[index] = gpd.patterns[index]*2;
    }
}

这是主机代码:

GPUPattern::GPUPatternData gpd;    
gpd.nodeInput = ptSet->getInputCount();
gpd.nodeOutput = ptSet->getOutputCount();
gpd.offest = gpd.nodeInput+gpd.nodeOutput;
gpd.patternCount = ptSet->getCount();
gpd.patterns = new cl_float [gpd.patternCount*gpd.offest];

GPUPattern::GPUPatternData gridC;
gridC.nodeInput = ptSet->getInputCount();
gridC.nodeOutput = ptSet->getOutputCount();
gridC.offest = gpd.nodeInput+gpd.nodeOutput;
gridC.patternCount = ptSet->getCount();
gridC.patterns = new cl_float [gpd.patternCount*gpd.offest];

所有数据都被初始化,然后用值初始化,然后传递给GPU

int elements = gpd.patternCount;
size_t ofsdf = sizeof(gridC);
size_t dataSize = sizeof(GPUPattern::GPUPatternData)+ (sizeof(cl_float)*elements);

cl_mem bufferA = clCreateBuffer(gpu.context,CL_MEM_READ_ONLY,dataSize,NULL,&err);
openCLErrorCheck(&err);
//Copy the buffer to the device
err = clEnqueueWriteBuffer(queue,bufferA,CL_TRUE,0,dataSize,(void*)&gpd,0,NULL,NULL);

//This buffer is being written to only
cl_mem bufferC = clCreateBuffer(gpu.context,CL_MEM_WRITE_ONLY,dataSize,NULL,&err);
openCLErrorCheck(&err);
err = clEnqueueWriteBuffer(queue,bufferC,CL_TRUE,0,dataSize,(void*)&gridC,0,NULL,NULL);

一切都已构建,我只检查停留在 0 的错误

cl_program program = clCreateProgramWithSource(gpu.context,1, (const char**) &kernelSource,NULL,&err);

////Build program
err = clBuildProgram(program, 0, NULL, NULL, NULL, NULL);

char build[2048];
clGetProgramBuildInfo(program, gpu.device, CL_PROGRAM_BUILD_LOG, 2048, build, NULL);

////Create kernal
cl_kernel kernal = clCreateKernel(program, "patternDataAddition",&err);

////Set kernal arguments
err  = clSetKernelArg(kernal,  0, sizeof(cl_mem), &bufferA);
err |= clSetKernelArg(kernal,  1, sizeof(cl_mem), &bufferC);

然后就开始了

size_t globalWorkSize = 1024;
size_t localWorkSize = 512;

err = clEnqueueNDRangeKernel(queue, kernal, 1, NULL, &globalWorkSize, &localWorkSize, 0, NULL, NULL); 

clFinish(queue);

到了这一步,一切都错了

err = clEnqueueReadBuffer(queue, bufferC, CL_TRUE, 0, dataSize, &gridC, 0, NULL, NULL);
clFinish(queue);

这种情况下的错误是 -5 (CL_OUT_OF_RESOURCES)。

如果我换行:

err = clEnqueueReadBuffer(queue, bufferC, CL_TRUE, 0, dataSize, &gridC, 0, NULL, 

到:

err = clEnqueueReadBuffer(queue, bufferC, CL_TRUE, 0, dataSize*1000, &gridC, 0, NULL, NULL);

我收到错误 -30 (CL_INVALID_VALUE)。

所以我的问题是为什么我在读回缓冲区时会出现错误。另外我不确定我是否无法使用指向我的浮点数组的指针,因为这可能会给我错误的sizeof() 用于datasize,这给了我错误的缓冲区大小。

【问题讨论】:

  • 分析得很好,但您的问题到底是什么?
  • 读回缓冲区时的错误。我不确定我是否无法使用指向我的浮点数组的指针,还是我的缓冲区大小错误

标签: c arrays opencl


【解决方案1】:

我知道它现在不是实际的,但我以其他方式解决了这个问题: 您为带有数据的结构分配内存的代码保持不变,但结构应该改为

typedef struct GPUPatternDataContatiner
{
    int nodeInput, nodeOutput, patternCount, offest;
    float patterns[0];
} GPUPatternData;

使用这个“功能”我为 OpenCL 创建了向量

【讨论】:

    【解决方案2】:

    您不能将包含指针的结构传递给 OpenCL

    http://www.khronos.org/registry/cl/specs/opencl-1.2.pdf(第 6.9 节)

    您可以像 Eric Bainville 指出的那样进行纠正,或者如果您的记忆力不是很严格,您可以执行类似的操作

    struct GPUPatternData
    {
        cl_int nInput,nOutput,patternCount, offest;
        cl_float patterns[MAX_SIZE];
    };
    

    编辑:如果内存是一个问题,那就好了。由于您只使用patternspatternCount,您可以从结构中复制模式并将它们分别传递给内核。

    struct GPUPatternData
        {
            cl_int nInput,nOutput,patternCount, offest;
            cl_float patterns*;
        };
    

    patternsgpd复制到GPU,并在GPU上为gridC中的patterns分配空间。 那么

    你可以单独传递缓冲区

    __kernel void patternDataAddition(int gpd_patternCount,
        __global const float * gpd_Patterns,
        __global float * gridC_Patterns) {
    
        int index = get_global_id(0);
        if(index < gpd_patternCount)
        {
            gridC_Patterns[index] = gpd_Patterns[index]*2;
        }
    }
    

    当你从内核返回时,直接将数据复制回gridC.patterns


    还有一个:

    您不必更改 CPU 结构。它保持不变。不过这部分

    size_t dataSize = sizeof(GPUPattern::GPUPatternData)+ (sizeof(cl_float)*elements);
    
    cl_mem bufferA = clCreateBuffer(gpu.context,CL_MEM_READ_ONLY,dataSize,NULL,&err);
    openCLErrorCheck(&err);
    //Copy the buffer to the device
    err = clEnqueueWriteBuffer(queue,bufferA,CL_TRUE,0,dataSize,(void*)&gpd,0,NULL,NULL);
    

    应该改成类似

    size_t dataSize = (sizeof(cl_float)*elements);  // HERE
    float* gpd_dataPointer = gpd.patterns;    // HERE
    
    cl_mem bufferA = clCreateBuffer(gpu.context,CL_MEM_READ_ONLY,dataSize,NULL,&err);
    openCLErrorCheck(&err);
    
    // Now use the gpd_dataPointer
    err = clEnqueueWriteBuffer(queue,bufferA,CL_TRUE,0,dataSize,(void*)&(gpd_dataPointer),0,NULL,NULL);
    

    gridC 也是如此

    当你复制回来时,将其复制到gridC_dataPointer AKA gridC.dataPointer

    然后像什么都没发生一样继续使用该结构。

    【讨论】:

    • 是他们的另一种选择吗?但是,由于我不想浪费大量内存,因此我需要将数据持久化,因为稍后(几分钟后)将访问它以进行计算
    • 我已将结构更改为 typedef struct GPUPatternDataContatiner { int nodeInput,nodeOutput,patternCount, offest;浮动模式[100]; } GPU模式数据;不管怎样,我把它传进去,我想读回整个结构。两个结构在每一侧都是相同的。我目前收到错误 -30 (CL_INVALID_VALUE)。其他一切都没有改变。基本上我需要那个结构,因为它可以省去很多麻烦
    • 我再次编辑了它。我希望这就是你要找的。​​span>
    【解决方案3】:

    问题可能出在结构内部的指针上。

    在这种情况下,我建议将 nInput,nOutput,patternCount,offset 作为内核参数传递,将模式作为浮点缓冲区传递:

    __kernel void patternDataAddition(int nInput,int nOutput,
        int patternCount,int offset,
        __global const float * inPatterns,
        __global float * outPatterns)
    

    【讨论】:

    • 你是不是建议我用我传入的数据创建一个结构体。这些数据将被许多内核持续使用并且需要持久化
    • 你的内核只会像你目前所做的那样更新 outPatterns[index]。
    • 是的,数据的持久性是该方法的问题。我更改数据只是为了检查它是否正确并且可以通过读出来访问
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-21
    • 2011-07-21
    相关资源
    最近更新 更多