2010-12-01 14 views
0

OpenCLは新しく、Nvidia 330グラフィックカードのOS X 10.6を実行しています。私はC++の布シミュレーションに取り組んでいます。私はそのコンパイルと実行のためのカーネルを作成しています。問題は、OpenCLを使用していないCPUよりも実行速度が遅いことです。この理由は、update()メソッドを呼び出して計算を行うたびに、コンテキストとデバイスを設定してから、カーネルをソースから再コンパイルするという理由があると思います。OpenCLカーネルで問題が発生するとプログラムが遅くなり、メモリーの問題が発生する可能性があります。

これを解決するために、必要なさまざまなOpenCLタイプを布シミュレーションクラスにカプセル化して試して保存してから、これらの値を設定するinitCL()を作成しました。その後、カーネルを実行するrunCL()を作成しました。不思議なことに、OpenCLを2つの方法に分けると、これは私にメモリの問題をもたらします。 initCL()とrunCL()が両方とも1つのメソッドに組み合わされていても、うまく動作しますが、これがちょっと残念です。

プログラムはコンパイルされて実行されますが、runCL()コードにマークされたポイントでSIGABRTまたはEXC BAD ACCESSが取得されます。私がSIGABRTを取得したとき、私はCL_INVALID_COMMAND_QUEUEというエラーが出ますが、なぜ私がこの2つの方法を分割した場合にのみ発生するのか、私の人生のためにはうまくいかないのです。アサーションが失敗したときにSIGABRTを取得することもありますが、これはバッファに書き込もうとしたときにメモリ不足アクセスエラーが発生するだけです。

また、誰かが私にこのより良い方法を教えてもらえますか、またはJITの再コンパイルが私のコードを遅くするものでないなら、私はこれをあまりにも凝視していたので、長いです!

おかげで、

ジョン

OpenCLの変数の初期化 コード:

int VPESimulationCloth::initCL(){ 
    // Find the CPU CL device, as a fallback 
    err = clGetDeviceIDs(NULL, CL_DEVICE_TYPE_CPU, 1, &device, NULL); 
    assert(err == CL_SUCCESS); 

    // Find the GPU CL device, this is what we really want 
// If there is no GPU device is CL capable, fall back to CPU 
    err = clGetDeviceIDs(NULL, CL_DEVICE_TYPE_GPU, 1, &device, NULL); 
if (err != CL_SUCCESS) err = clGetDeviceIDs(NULL, CL_DEVICE_TYPE_CPU, 1, &device, NULL); 
assert(device); 

// Get some information about the returned device 
cl_char vendor_name[1024] = {0}; 
cl_char device_name[1024] = {0}; 
err = clGetDeviceInfo(device, CL_DEVICE_VENDOR, sizeof(vendor_name), 
       vendor_name, &returned_size); 
err |= clGetDeviceInfo(device, CL_DEVICE_NAME, sizeof(device_name), 
       device_name, &returned_size); 
assert(err == CL_SUCCESS); 
//printf("Connecting to %s %s...\n", vendor_name, device_name); 

// Now create a context to perform our calculation with the 
// specified device 
context = clCreateContext(0, 1, &device, NULL, NULL, &err); 
assert(err == CL_SUCCESS); 

// And also a command queue for the context 
cmd_queue = clCreateCommandQueue(context, device, 0, NULL); 

// Load the program source from disk 
// The kernel/program should be in the resource directory 
const char * filename = "clothSimKernel.cl"; 
char *program_source = load_program_source(filename); 


program[0] = clCreateProgramWithSource(context, 1, (const char**)&program_source, 
          NULL, &err); 
if (!program[0]) 
{ 
    printf("Error: Failed to create compute program!\n"); 
    return EXIT_FAILURE; 
} 
assert(err == CL_SUCCESS); 

err = clBuildProgram(program[0], 0, NULL, NULL, NULL, NULL); 
if (err != CL_SUCCESS) 
{ 
    char build[2048]; 
    clGetProgramBuildInfo(program[0], device, CL_PROGRAM_BUILD_LOG, 2048, build, NULL); 
    printf("Build Log:\n%s\n",build); 
    if (err == CL_BUILD_PROGRAM_FAILURE) { 
     printf("CL_BUILD_PROGRAM_FAILURE\n"); 
    } 
} 
if (err != CL_SUCCESS) { 
    cout<<getErrorDesc(err)<<endl; 
} 
assert(err == CL_SUCCESS); 
//writeBinaries(); 
// Now create the kernel "objects" that we want to use in the example file 
kernel[0] = clCreateKernel(program[0], "clothSimulation", &err); 

} 

方法カーネル コードを実行するには:

int VPESimulationCloth::runCL(){ 

// Find the GPU CL device, this is what we really want 
// If there is no GPU device is CL capable, fall back to CPU 
err = clGetDeviceIDs(NULL, CL_DEVICE_TYPE_GPU, 1, &device, NULL); 
if (err != CL_SUCCESS) err = clGetDeviceIDs(NULL, CL_DEVICE_TYPE_CPU, 1, &device, NULL); 
assert(device); 

// Get some information about the returned device 
cl_char vendor_name[1024] = {0}; 
cl_char device_name[1024] = {0}; 
err = clGetDeviceInfo(device, CL_DEVICE_VENDOR, sizeof(vendor_name), 
       vendor_name, &returned_size); 
err |= clGetDeviceInfo(device, CL_DEVICE_NAME, sizeof(device_name), 
       device_name, &returned_size); 
assert(err == CL_SUCCESS); 
//printf("Connecting to %s %s...\n", vendor_name, device_name); 

// Now create a context to perform our calculation with the 
// specified device 

//cmd_queue = clCreateCommandQueue(context, device, 0, NULL); 
//memory allocation 
cl_mem nowPos_mem, prevPos_mem, rForce_mem, mass_mem, passive_mem, canMove_mem,numPart_mem, theForces_mem, numForces_mem, drag_mem, answerPos_mem; 

// Allocate memory on the device to hold our data and store the results into 
buffer_size = sizeof(float4) * numParts; 

// Input arrays 
//------------------------------------ 
// This is where the error occurs 
nowPos_mem = clCreateBuffer(context, CL_MEM_READ_ONLY, buffer_size, NULL, NULL); 
err = clEnqueueWriteBuffer(cmd_queue, nowPos_mem, CL_TRUE, 0, buffer_size, 
        (void*)nowPos, 0, NULL, NULL); 
if (err != CL_SUCCESS) { 
    cout<<getErrorDesc(err)<<endl; 
} 
assert(err == CL_SUCCESS); 
//------------------------------------ 
prevPos_mem = clCreateBuffer(context, CL_MEM_READ_ONLY, buffer_size, NULL, NULL); 
err = clEnqueueWriteBuffer(cmd_queue, prevPos_mem, CL_TRUE, 0, buffer_size, 
        (void*)prevPos, 0, NULL, NULL); 
assert(err == CL_SUCCESS); 
rForce_mem = clCreateBuffer(context, CL_MEM_READ_ONLY, buffer_size, NULL, NULL); 
err = clEnqueueWriteBuffer(cmd_queue, rForce_mem, CL_TRUE, 0, buffer_size, 
        (void*)rForce, 0, NULL, NULL); 
assert(err == CL_SUCCESS); 
mass_mem = clCreateBuffer(context, CL_MEM_READ_ONLY, buffer_size, NULL, NULL); 
err = clEnqueueWriteBuffer(cmd_queue, mass_mem, CL_TRUE, 0, buffer_size, 
        (void*)mass, 0, NULL, NULL); 
assert(err == CL_SUCCESS); 
answerPos_mem = clCreateBuffer(context, CL_MEM_READ_WRITE, buffer_size, NULL, NULL); 
//uint buffer 
buffer_size = sizeof(uint) * numParts; 
passive_mem = clCreateBuffer(context, CL_MEM_READ_ONLY, buffer_size, NULL, NULL); 
err = clEnqueueWriteBuffer(cmd_queue, passive_mem, CL_TRUE, 0, buffer_size, 
        (void*)passive, 0, NULL, NULL); 
assert(err == CL_SUCCESS); 
canMove_mem = clCreateBuffer(context, CL_MEM_READ_ONLY, buffer_size, NULL, NULL); 
err = clEnqueueWriteBuffer(cmd_queue, canMove_mem, CL_TRUE, 0, buffer_size, 
        (void*)canMove, 0, NULL, NULL); 
assert(err == CL_SUCCESS); 

buffer_size = sizeof(float4) * numForces; 
theForces_mem = clCreateBuffer(context, CL_MEM_READ_ONLY, buffer_size, NULL, NULL); 
err = clEnqueueWriteBuffer(cmd_queue, theForces_mem, CL_TRUE, 0, buffer_size, 
        (void*)theForces, 0, NULL, NULL); 
assert(err == CL_SUCCESS); 

//drag float 
buffer_size = sizeof(float); 
drag_mem = clCreateBuffer(context, CL_MEM_READ_ONLY, buffer_size, NULL, NULL); 
err |= clEnqueueWriteBuffer(cmd_queue, drag_mem, CL_TRUE, 0, buffer_size, 
        (void*)drag, 0, NULL, NULL); 
assert(err == CL_SUCCESS); 

// Now setup the arguments to our kernel 
err = clSetKernelArg(kernel[0], 0, sizeof(cl_mem), &nowPos_mem); 
err |= clSetKernelArg(kernel[0], 1, sizeof(cl_mem), &prevPos_mem); 
err |= clSetKernelArg(kernel[0], 2, sizeof(cl_mem), &rForce_mem); 
err |= clSetKernelArg(kernel[0], 3, sizeof(cl_mem), &mass_mem); 
err |= clSetKernelArg(kernel[0], 4, sizeof(cl_mem), &passive_mem); 
err |= clSetKernelArg(kernel[0], 5, sizeof(cl_mem), &canMove_mem); 
err |= clSetKernelArg(kernel[0], 6, sizeof(cl_mem), &numParts); 
err |= clSetKernelArg(kernel[0], 7, sizeof(cl_mem), &theForces_mem); 
err |= clSetKernelArg(kernel[0], 8, sizeof(cl_mem), &numForces); 
err |= clSetKernelArg(kernel[0], 9, sizeof(cl_mem), &drag_mem); 
err |= clSetKernelArg(kernel[0], 10, sizeof(cl_mem), &answerPos_mem); 
if (err != CL_SUCCESS) { 
    cout<<getErrorDesc(err)<<endl; 
} 
assert(err == CL_SUCCESS); 
// Run the calculation by enqueuing it and forcing the 
// command queue to complete the task 
size_t global_work_size = numParts; 
size_t local_work_size = global_work_size/8; 
err = clEnqueueNDRangeKernel(cmd_queue, kernel[0], 1, NULL, 
        &global_work_size, &local_work_size, 0, NULL, NULL); 
if (err != CL_SUCCESS) { 
    cout<<getErrorDesc(err)<<endl; 
} 

assert(err == CL_SUCCESS); 
//clFinish(cmd_queue); 

// Once finished read back the results from the answer 
// array into the results array 
//reset the buffer first 
buffer_size = sizeof(float4) * numParts; 
err = clEnqueueReadBuffer(cmd_queue, answerPos_mem, CL_TRUE, 0, buffer_size, 
        answerPos, 0, NULL, NULL); 
if (err != CL_SUCCESS) { 
    cout<<getErrorDesc(err)<<endl; 
} 


//cl mem 
clReleaseMemObject(nowPos_mem); 
clReleaseMemObject(prevPos_mem); 
clReleaseMemObject(rForce_mem); 
clReleaseMemObject(mass_mem); 
clReleaseMemObject(passive_mem); 
clReleaseMemObject(canMove_mem); 
clReleaseMemObject(theForces_mem); 
clReleaseMemObject(drag_mem); 
clReleaseMemObject(answerPos_mem); 
clReleaseCommandQueue(cmd_queue); 
clReleaseContext(context); 
assert(err == CL_SUCCESS); 
return err; 

} 
+0

質問もここに掲載http://www.khronos.org/message_boards/viewtopic.php?f=37&t=3296 –

答えて

1

問題を解決します! runCL()メソッドの一番下では、私はすべてのcl型を解放していましたが、私はいくつかのcl_memを解放していましたが、より詳細な検査では文脈などを解放していました。

これは、Khronosのフォーラムでandrew.brownswordに感謝の意を表します。

+1

戻ってクラッシュをどのように解決したか教えてくれてありがとう。 – Tom

0

よくある問題を修正しました。

性能に関しては、numPartsが多数ですか?デバイスを仕事で充実させるためには、グローバルワークサイズが大きくなければなりません。何万もの。理想的には、ローカルワークサイズ(線形化された場合)は32の倍数になります。最良の値はカーネルによって異なります。 は大きすぎると起動失敗を引き起こす可能性があるため(最大限のローカルワークサイズなどの情報を問い合わせることができます)、カーネルに依存してローカルワークサイズを一定値またはある値に設定するのが一般的です特定のカーネルと特定のデバイスで)。

+0

それを指摘してくれてありがとう。私は前にCPU上で実行していたので、かなり小さな32x32パッチの布でこれをテストしていました。私は主な問題を修正し、すべてをgpuに移して布のサイズを増やすことができた後、このワークサイズの問題を発見しました。あなたが提案した定数を使って試してみましょう。最良の値を見つけるためにいくつかのクエリを実行します。 –

関連する問題