3

現在、GPUに渡して2を掛けたいデータがいくつかあります。

ここで見ることができる構造体を作成しました:

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

この構造体には、floatの配列が含まれている必要があります。フロートの配列は、ユーザーが指定するため、実行時までわかりません。

ホストコード:

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)が発生します。

だから私の質問は、なぜバッファを読み戻すときにエラーが発生するのかということです。また、float配列へのポインタを使用できないかどうかもわかりません。これにより、間違ったsizeof()使用法が使用されdatasize、間違ったバッファサイズが発生する可能性があります。

4

3 に答える 3

5

ポインタを含む構造体を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];
};

編集:メモリが問題である場合はOK。patternsを使用するだけなのでpatternCount、構造体からパターンをコピーして、カーネルに個別に渡すことができます。

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

patternsからGPUにコピーし、GPUgpdにスペースを割り当てます。それからpatternsgridC

バッファを個別に渡すことができます

__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直接にコピーして戻します


もう1つ:

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_dataPointerAKAにコピーしてくださいgridC.dataPointer

そして、何も起こらなかったかのように構造体を使い続けます。

于 2013-03-26T17:30:14.273 に答える
1

問題はおそらく構造体内のポインタにあります。

この場合、nInput、nOutput、patternCount、offsetをカーネル引数として渡し、patternsをfloatのバッファーとして渡すことをお勧めします。

__kernel void patternDataAddition(int nInput,int nOutput,
    int patternCount,int offset,
    __global const float * inPatterns,
    __global float * outPatterns)
于 2013-03-26T16:13:55.250 に答える
-1

今は実際ではないことはわかっていますが、この問題を別の方法で渡しました。データを含む構造体の割り当てメモリのコードは同じままですが、構造体を次のように変更する必要があります。

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

この「機能」を使用して、OpenCLのベクターを作成しました

于 2014-12-24T07:07:26.050 に答える