私は最近OpenCLで遊んでいますが、グローバルメモリのみを使用するシンプルなカーネルを書くことができます。ここで、ローカルメモリの使用を開始したいのですが、get_local_size()
およびget_local_id()
を使用して一度に1つの「チャンク」の出力を計算する方法がわかりません。
たとえば、AppleのOpenCL Hello Worldサンプルカーネルをローカルメモリを使用するものに変換したいとします。どうしますか?元のカーネルソースは次のとおりです。
__kernel square(
__global float *input,
__global float *output,
const unsigned int count)
{
int i = get_global_id(0);
if (i < count)
output[i] = input[i] * input[i];
}
この例を簡単にローカルメモリの使用方法を示すものに変換できない場合は、他の簡単な例でも実行できます。
NVIDIAまたはAMD SDKのサンプルをご覧ください。正しい方向を示しているはずです。行列転置は、たとえばローカルメモリを使用します。
スクエアリングカーネルを使用すると、中間バッファーにデータをステージングできます。追加パラメーターを渡すことを忘れないでください。
__kernel square(
__global float *input,
__global float *output,
__local float *temp,
const unsigned int count)
{
int gtid = get_global_id(0);
int ltid = get_local_id(0);
if (gtid < count)
{
temp[ltid] = input[gtid];
// if the threads were reading data from other threads, then we would
// want a barrier here to ensure the write completes before the read
output[gtid] = temp[ltid] * temp[ltid];
}
}
ローカルメモリのサイズが一定の場合、これを行う別の可能性があります。カーネルパラメーターリストでポインターを使用せずに、ローカルバッファーを__localと宣言するだけでカーネル内で宣言できます。
__local float localBuffer[1024];
これにより、clSetKernelArg呼び出しが少なくなるため、コードが削除されます。
OpenCLでは、ローカルメモリは、ワークグループ内のすべてのワークアイテム間でデータを共有するためのものです。また、通常、ローカルメモリデータを使用する前にバリア呼び出しを行う必要があります(たとえば、1つの作業項目が他の作業項目によって書き込まれたローカルメモリデータを読み取りたい場合)。障壁はハードウェアに高価です。データの読み取り/書き込みを繰り返すには、ローカルメモリを使用する必要があることに注意してください。銀行の紛争はできる限り避けるべきです。
ローカルメモリに注意しないと、グローバルメモリを使用するよりもパフォーマンスが低下する場合があります。