3

たぶん(あるいはそうではないかもしれませんが)私は間違った方法で何かをしますが、CPUよりもGPUでかなり高速に実行されているにもかかわらず、OpenClカーネルから良いパフォーマンスを得ることができないようです。

説明させてください。

CPUカーネルの実行時間は約100msです。
GPUカーネルの実行時間は約8ミリ秒です。

clCreateCommandQueue上記はwithCL_QUEUE_PROFILING_ENABLEフラグを使用して測定されました。

しかし、問題は、カーネルを繰り返し呼び出す(エンキューする)ために必要な時間です。

CPUでの200カーネル呼び出し:〜19秒
GPUでの200カーネル呼び出し:〜18秒

gettimeofday上記は、200ループの前後の呼び出しで測定されました。そして、ループの直後にclFinish、200個のエンキューされたカーネルが完了するまで待機するための呼び出しがありました。
さらに、時間はカーネルのエンキューと実行についてのみ測定され、カーネルとの間のデータ転送は含まれていませんでした。

ループは次のとおりです。

size_t global_item_size = LIST_SIZE;
Start_Clock(&startTime);
for(int k=0; k<200; k++)
{
    // Execute the OpenCL kernel on the list
    ret = clEnqueueNDRangeKernel (command_queue, kernel, 1, NULL, &global_item_size, NULL, 0, NULL, &event);        
}   
clFinish(command_queue);    
printf("] (in %0.4fs)\n", Stop_Clock(&startTime));

カーネルへの200回の呼び出しに約18秒かかる場合、GPU上のカーネルがCPU上のカーネルよりも数倍高速であることはまったく関係ありません...

私は何が間違っているのですか?


編集

追加のテストをいくつか行いましたが、実際に計算結果を出力バッファーに割り当てると、オーバーヘッドが発生しているようです。

このカーネル

__kernel void test_kernel(__global const float *A, __global const float *B, __global float *C) 
{
    // Get the index of the current element to be processed
    int i = get_global_id(0);

    // Do the work
    C[i] = sqrt(sin(A[i]) + tan(B[i]));
}

200回実行すると上記のようなタイミングになります。しかし、C[i]行を変更すると
float z = sqrt(sin(A[i]) + tan(B[i]));
、このカーネルはCPUで0.3秒、GPUで2.6秒かかります。

面白い。
結果をテーブルに収集し、最後のカーネル呼び出しの実行時にのみ__local出力バッファーに割り当てることで、実行を高速化できるでしょうか。C(200番目のエンキューされたカーネルではなく、最後のグローバルIDを持つカーネル)

4

0 に答える 0