web-dev-qa-db-ja.com

OpenCLでローカルメモリを宣言する方法は?

以下のOpenCLカーネルを、1000000 x100の2次元グローバルワークサイズと1x100のローカルワークサイズで実行しています。

__kernel void myKernel(
        const int length, 
        const int height, 
        and a bunch of other parameters) {

    //declare some local arrays to be shared by all 100 work item in this group
    __local float LP [length];
    __local float LT [height];
    __local int bitErrors = 0;
    __local bool failed = false;

    //here come my actual computations which utilize the space in LP and LT
}

ただし、パラメータlengthおよびheightはコンパイル時に不明であるため、これはコンパイルを拒否します。しかし、これを正しく行う方法は私にはまったくわかりません。 memallocでポインターを使用する必要がありますか?メモリがワークグループ全体に1回だけ割り当てられ、ワークアイテムごとに1回割り当てられないように、これを処理するにはどうすればよいですか?

必要なのは、ワークグループ全体で共有される2つのfloat配列、1つのintと1つのブール値です(つまり、100個の作業項目すべて)。しかし、私はこれを正しく行う方法を見つけることができません...

15
user1111929

比較的簡単です。ローカル配列を引数としてカーネルに渡すことができます。

kernel void myKernel(const int length, const int height, local float* LP, 
                     local float* LT, a bunch of other parameters) 

次に、valueNULLと引数に割り当てるサイズ(バイト単位)に等しいsizeを使用してkernelargumentを設定します。したがって、次のようになります。

clSetKernelArg(kernel, 2, length * sizeof(cl_float), NULL);
clSetKernelArg(kernel, 2, height* sizeof(cl_float), NULL);

ローカルメモリは(プライベートではなく)常にワークグループによって共有されるため、boolintは問題ないと思いますが、そうでない場合は、いつでも引数として渡すことができます。

あなたの問題とは実際には関係ありませんが(これを実行する予定のハードウェアがわからないため、必ずしも関係ありません)、少なくともgpusは、特定の2の累乗の倍数ではない作業サイズを特に好みません(I nvidiaの場合は32、AMDの場合は64だったと思います)。つまり、おそらく128項目のワークグループが作成され、そのうち最後の28項目は基本的に無駄になります。したがって、gpuでopenclを実行している場合、サイズ128のワークグループを直接使用すると(グローバルワークサイズを適切に変更すると)、パフォーマンスが向上する可能性があります。

補足として:なぜ誰もがkernel, local and globalにアンダースコアのバリアントを使用するのか理解できませんでしたが、私にははるかに醜いようです。

25
Grizzly

特に配列ではなく単純な変数である場合は、カーネルの外部にすべてのローカルメモリを割り当てる必要はありません。

コードをコンパイルできない理由は、OpenCLがローカルメモリの初期化をサポートしていないためです。これはドキュメントで指定されています( https://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/local.html )。 CUDAでも実行できません( 共有メモリ配列のデフォルト値を設定する方法はありますか?


ps:Grizzlyからの回答で十分であり、コメントとして投稿できればよいのですが、評判ポリシーによって制限されています。ごめんなさい。

1
youwei

次のように配列を宣言することもできます。

__local float LP[LENGTH];

そして、LENGTHをカーネルコンパイルの定義として渡します。

int lp_size = 128; // this is an example; could be dynamically calculated
char compileArgs[64];
sprintf(compileArgs, "-DLENGTH=%d", lp_size);
clBuildProgram(program, 0, NULL, compileArgs, NULL, NULL);
1
David B